opencode-aicodewith-auth 0.1.2 → 0.1.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/README.md CHANGED
@@ -59,13 +59,13 @@ User Request → OpenCode → Plugin Auth Hook → Route by Model:
59
59
 
60
60
  ## 支持的模型
61
61
 
62
- | 模型 ID | 显示名称 | 适合场景 |
63
- |---------|---------|---------|
64
- | `aicodewith/gpt-5.2-codex` | GPT-5.2 Codex | 日常编程、代码生成 |
65
- | `aicodewith/gpt-5.2` | GPT-5.2 | 架构设计、逻辑推理 |
66
- | `aicodewith/claude-sonnet-4-5-20250929` | Claude Sonnet 4.5 | 代码审查、文档查询 |
67
- | `aicodewith/claude-opus-4-5-20251101` | Claude Opus 4.5 | 复杂任务、深度思考 |
68
- | `aicodewith/gemini-3-pro-high` | Gemini 3 Pro | 前端 UI、多模态任务 |
62
+ | 模型 ID | 显示名称 | 图片输入 | 适合场景 |
63
+ |---------|---------|:-------:|---------|
64
+ | `aicodewith/gpt-5.2-codex` | GPT-5.2 Codex | ✅ | 日常编程、代码生成 |
65
+ | `aicodewith/gpt-5.2` | GPT-5.2 | ✅ | 架构设计、逻辑推理 |
66
+ | `aicodewith/claude-sonnet-4-5-20250929` | Claude Sonnet 4.5 | ✅ | 代码审查、文档查询 |
67
+ | `aicodewith/claude-opus-4-5-20251101` | Claude Opus 4.5 | ✅ | 复杂任务、深度思考 |
68
+ | `aicodewith/gemini-3-pro-high` | Gemini 3 Pro | ✅ | 前端 UI、多模态任务 |
69
69
 
70
70
  ---
71
71
 
package/dist/index.js CHANGED
@@ -60,8 +60,8 @@ var aicodewith = createAicodewith();
60
60
 
61
61
  // index.ts
62
62
  import { mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
63
- import path from "path";
64
- import os from "os";
63
+ import path4 from "path";
64
+ import os3 from "os";
65
65
 
66
66
  // lib/constants.ts
67
67
  var PLUGIN_NAME = "opencode-aicodewith-auth";
@@ -993,9 +993,440 @@ async function handleSuccessResponse(response, isStreaming) {
993
993
  });
994
994
  }
995
995
 
996
+ // lib/hooks/auto-update/index.ts
997
+ import { spawn } from "child_process";
998
+
999
+ // lib/hooks/auto-update/checker.ts
1000
+ import * as fs2 from "fs";
1001
+ import * as path2 from "path";
1002
+ import { fileURLToPath as fileURLToPath2 } from "url";
1003
+
1004
+ // lib/hooks/auto-update/constants.ts
1005
+ import * as path from "path";
1006
+ import * as os from "os";
1007
+ import * as fs from "fs";
1008
+ var PACKAGE_NAME = "opencode-aicodewith-auth";
1009
+ var NPM_REGISTRY_URL = `https://registry.npmjs.org/-/package/${PACKAGE_NAME}/dist-tags`;
1010
+ var NPM_FETCH_TIMEOUT = 5000;
1011
+ function getCacheDir() {
1012
+ if (process.platform === "win32") {
1013
+ return path.join(process.env.LOCALAPPDATA ?? os.homedir(), "opencode");
1014
+ }
1015
+ return path.join(os.homedir(), ".cache", "opencode");
1016
+ }
1017
+ var CACHE_DIR3 = getCacheDir();
1018
+ var INSTALLED_PACKAGE_JSON = path.join(CACHE_DIR3, "node_modules", PACKAGE_NAME, "package.json");
1019
+ function getUserConfigDir() {
1020
+ if (process.platform === "win32") {
1021
+ const crossPlatformDir = path.join(os.homedir(), ".config");
1022
+ const appdataDir = process.env.APPDATA ?? path.join(os.homedir(), "AppData", "Roaming");
1023
+ const crossPlatformConfig = path.join(crossPlatformDir, "opencode", "opencode.json");
1024
+ const crossPlatformConfigJsonc = path.join(crossPlatformDir, "opencode", "opencode.jsonc");
1025
+ if (fs.existsSync(crossPlatformConfig) || fs.existsSync(crossPlatformConfigJsonc)) {
1026
+ return crossPlatformDir;
1027
+ }
1028
+ return appdataDir;
1029
+ }
1030
+ return process.env.XDG_CONFIG_HOME ?? path.join(os.homedir(), ".config");
1031
+ }
1032
+ function getWindowsAppdataDir() {
1033
+ if (process.platform !== "win32")
1034
+ return null;
1035
+ return process.env.APPDATA ?? path.join(os.homedir(), "AppData", "Roaming");
1036
+ }
1037
+ var USER_CONFIG_DIR = getUserConfigDir();
1038
+ var USER_OPENCODE_CONFIG = path.join(USER_CONFIG_DIR, "opencode", "opencode.json");
1039
+ var USER_OPENCODE_CONFIG_JSONC = path.join(USER_CONFIG_DIR, "opencode", "opencode.jsonc");
1040
+
1041
+ // lib/hooks/auto-update/checker.ts
1042
+ import * as os2 from "os";
1043
+ var LOG_PREFIX = `[${PACKAGE_NAME}:auto-update]`;
1044
+ function log(...args) {
1045
+ if (process.env.DEBUG?.includes(PACKAGE_NAME) || process.env.DEBUG?.includes("auto-update")) {
1046
+ console.log(LOG_PREFIX, ...args);
1047
+ }
1048
+ }
1049
+ function stripJsonComments(json) {
1050
+ return json.replace(/\\"|"(?:\\"|[^"])*"|(\/\/.*|\/\*[\s\S]*?\*\/)/g, (m, g) => g ? "" : m).replace(/,(\s*[}\]])/g, "$1");
1051
+ }
1052
+ function getConfigPaths(directory) {
1053
+ const paths = [
1054
+ path2.join(directory, ".opencode", "opencode.json"),
1055
+ path2.join(directory, ".opencode", "opencode.jsonc"),
1056
+ USER_OPENCODE_CONFIG,
1057
+ USER_OPENCODE_CONFIG_JSONC
1058
+ ];
1059
+ if (process.platform === "win32") {
1060
+ const crossPlatformDir = path2.join(os2.homedir(), ".config");
1061
+ const appdataDir = getWindowsAppdataDir();
1062
+ if (appdataDir) {
1063
+ const alternateDir = USER_CONFIG_DIR === crossPlatformDir ? appdataDir : crossPlatformDir;
1064
+ const alternateConfig = path2.join(alternateDir, "opencode", "opencode.json");
1065
+ const alternateConfigJsonc = path2.join(alternateDir, "opencode", "opencode.jsonc");
1066
+ if (!paths.includes(alternateConfig)) {
1067
+ paths.push(alternateConfig);
1068
+ }
1069
+ if (!paths.includes(alternateConfigJsonc)) {
1070
+ paths.push(alternateConfigJsonc);
1071
+ }
1072
+ }
1073
+ }
1074
+ return paths;
1075
+ }
1076
+ function getLocalDevPath(directory) {
1077
+ for (const configPath of getConfigPaths(directory)) {
1078
+ try {
1079
+ if (!fs2.existsSync(configPath))
1080
+ continue;
1081
+ const content = fs2.readFileSync(configPath, "utf-8");
1082
+ const config = JSON.parse(stripJsonComments(content));
1083
+ const plugins = config.plugin ?? [];
1084
+ for (const entry of plugins) {
1085
+ if (entry.startsWith("file://") && entry.includes(PACKAGE_NAME)) {
1086
+ try {
1087
+ return fileURLToPath2(entry);
1088
+ } catch {
1089
+ return entry.replace("file://", "");
1090
+ }
1091
+ }
1092
+ }
1093
+ } catch {
1094
+ continue;
1095
+ }
1096
+ }
1097
+ return null;
1098
+ }
1099
+ function findPackageJsonUp(startPath) {
1100
+ try {
1101
+ const stat = fs2.statSync(startPath);
1102
+ let dir = stat.isDirectory() ? startPath : path2.dirname(startPath);
1103
+ for (let i = 0;i < 10; i++) {
1104
+ const pkgPath = path2.join(dir, "package.json");
1105
+ if (fs2.existsSync(pkgPath)) {
1106
+ try {
1107
+ const content = fs2.readFileSync(pkgPath, "utf-8");
1108
+ const pkg = JSON.parse(content);
1109
+ if (pkg.name === PACKAGE_NAME)
1110
+ return pkgPath;
1111
+ } catch {}
1112
+ }
1113
+ const parent = path2.dirname(dir);
1114
+ if (parent === dir)
1115
+ break;
1116
+ dir = parent;
1117
+ }
1118
+ } catch {}
1119
+ return null;
1120
+ }
1121
+ function getLocalDevVersion(directory) {
1122
+ const localPath = getLocalDevPath(directory);
1123
+ if (!localPath)
1124
+ return null;
1125
+ try {
1126
+ const pkgPath = findPackageJsonUp(localPath);
1127
+ if (!pkgPath)
1128
+ return null;
1129
+ const content = fs2.readFileSync(pkgPath, "utf-8");
1130
+ const pkg = JSON.parse(content);
1131
+ return pkg.version ?? null;
1132
+ } catch {
1133
+ return null;
1134
+ }
1135
+ }
1136
+ function findPluginEntry(directory) {
1137
+ for (const configPath of getConfigPaths(directory)) {
1138
+ try {
1139
+ if (!fs2.existsSync(configPath))
1140
+ continue;
1141
+ const content = fs2.readFileSync(configPath, "utf-8");
1142
+ const config = JSON.parse(stripJsonComments(content));
1143
+ const plugins = config.plugin ?? [];
1144
+ for (const entry of plugins) {
1145
+ if (entry === PACKAGE_NAME) {
1146
+ return { entry, isPinned: false, pinnedVersion: null, configPath };
1147
+ }
1148
+ if (entry.startsWith(`${PACKAGE_NAME}@`)) {
1149
+ const pinnedVersion = entry.slice(PACKAGE_NAME.length + 1);
1150
+ const isPinned = pinnedVersion !== "latest";
1151
+ return { entry, isPinned, pinnedVersion: isPinned ? pinnedVersion : null, configPath };
1152
+ }
1153
+ }
1154
+ } catch {
1155
+ continue;
1156
+ }
1157
+ }
1158
+ return null;
1159
+ }
1160
+ function getCachedVersion() {
1161
+ try {
1162
+ if (fs2.existsSync(INSTALLED_PACKAGE_JSON)) {
1163
+ const content = fs2.readFileSync(INSTALLED_PACKAGE_JSON, "utf-8");
1164
+ const pkg = JSON.parse(content);
1165
+ if (pkg.version)
1166
+ return pkg.version;
1167
+ }
1168
+ } catch {}
1169
+ try {
1170
+ const currentDir = path2.dirname(fileURLToPath2(import.meta.url));
1171
+ const pkgPath = findPackageJsonUp(currentDir);
1172
+ if (pkgPath) {
1173
+ const content = fs2.readFileSync(pkgPath, "utf-8");
1174
+ const pkg = JSON.parse(content);
1175
+ if (pkg.version)
1176
+ return pkg.version;
1177
+ }
1178
+ } catch (err) {
1179
+ log("Failed to resolve version from current directory:", err);
1180
+ }
1181
+ return null;
1182
+ }
1183
+ function updatePinnedVersion(configPath, oldEntry, newVersion) {
1184
+ try {
1185
+ const content = fs2.readFileSync(configPath, "utf-8");
1186
+ const newEntry = `${PACKAGE_NAME}@${newVersion}`;
1187
+ const pluginMatch = content.match(/"plugin"\s*:\s*\[/);
1188
+ if (!pluginMatch || pluginMatch.index === undefined) {
1189
+ log(`No "plugin" array found in ${configPath}`);
1190
+ return false;
1191
+ }
1192
+ const startIdx = pluginMatch.index + pluginMatch[0].length;
1193
+ let bracketCount = 1;
1194
+ let endIdx = startIdx;
1195
+ for (let i = startIdx;i < content.length && bracketCount > 0; i++) {
1196
+ if (content[i] === "[")
1197
+ bracketCount++;
1198
+ else if (content[i] === "]")
1199
+ bracketCount--;
1200
+ endIdx = i;
1201
+ }
1202
+ const before = content.slice(0, startIdx);
1203
+ const pluginArrayContent = content.slice(startIdx, endIdx);
1204
+ const after = content.slice(endIdx);
1205
+ const escapedOldEntry = oldEntry.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1206
+ const regex = new RegExp(`["']${escapedOldEntry}["']`);
1207
+ if (!regex.test(pluginArrayContent)) {
1208
+ log(`Entry "${oldEntry}" not found in plugin array of ${configPath}`);
1209
+ return false;
1210
+ }
1211
+ const updatedPluginArray = pluginArrayContent.replace(regex, `"${newEntry}"`);
1212
+ const updatedContent = before + updatedPluginArray + after;
1213
+ if (updatedContent === content) {
1214
+ log(`No changes made to ${configPath}`);
1215
+ return false;
1216
+ }
1217
+ fs2.writeFileSync(configPath, updatedContent, "utf-8");
1218
+ log(`Updated ${configPath}: ${oldEntry} \u2192 ${newEntry}`);
1219
+ return true;
1220
+ } catch (err) {
1221
+ log(`Failed to update config file ${configPath}:`, err);
1222
+ return false;
1223
+ }
1224
+ }
1225
+ async function getLatestVersion() {
1226
+ const controller = new AbortController;
1227
+ const timeoutId = setTimeout(() => controller.abort(), NPM_FETCH_TIMEOUT);
1228
+ try {
1229
+ const response = await fetch(NPM_REGISTRY_URL, {
1230
+ signal: controller.signal,
1231
+ headers: { Accept: "application/json" }
1232
+ });
1233
+ if (!response.ok)
1234
+ return null;
1235
+ const data = await response.json();
1236
+ return data.latest ?? null;
1237
+ } catch {
1238
+ return null;
1239
+ } finally {
1240
+ clearTimeout(timeoutId);
1241
+ }
1242
+ }
1243
+
1244
+ // lib/hooks/auto-update/cache.ts
1245
+ import * as fs3 from "fs";
1246
+ import * as path3 from "path";
1247
+ function stripTrailingCommas(json) {
1248
+ return json.replace(/,(\s*[}\]])/g, "$1");
1249
+ }
1250
+ function removeFromBunLock(packageName) {
1251
+ const lockPath = path3.join(CACHE_DIR3, "bun.lock");
1252
+ if (!fs3.existsSync(lockPath))
1253
+ return false;
1254
+ try {
1255
+ const content = fs3.readFileSync(lockPath, "utf-8");
1256
+ const lock = JSON.parse(stripTrailingCommas(content));
1257
+ let modified = false;
1258
+ if (lock.workspaces?.[""]?.dependencies?.[packageName]) {
1259
+ delete lock.workspaces[""].dependencies[packageName];
1260
+ modified = true;
1261
+ }
1262
+ if (lock.packages?.[packageName]) {
1263
+ delete lock.packages[packageName];
1264
+ modified = true;
1265
+ }
1266
+ if (modified) {
1267
+ fs3.writeFileSync(lockPath, JSON.stringify(lock, null, 2));
1268
+ log(`Removed from bun.lock: ${packageName}`);
1269
+ }
1270
+ return modified;
1271
+ } catch {
1272
+ return false;
1273
+ }
1274
+ }
1275
+ function invalidatePackage(packageName = PACKAGE_NAME) {
1276
+ try {
1277
+ const pkgDir = path3.join(CACHE_DIR3, "node_modules", packageName);
1278
+ const pkgJsonPath = path3.join(CACHE_DIR3, "package.json");
1279
+ let packageRemoved = false;
1280
+ let dependencyRemoved = false;
1281
+ let lockRemoved = false;
1282
+ if (fs3.existsSync(pkgDir)) {
1283
+ fs3.rmSync(pkgDir, { recursive: true, force: true });
1284
+ log(`Package removed: ${pkgDir}`);
1285
+ packageRemoved = true;
1286
+ }
1287
+ if (fs3.existsSync(pkgJsonPath)) {
1288
+ const content = fs3.readFileSync(pkgJsonPath, "utf-8");
1289
+ const pkgJson = JSON.parse(content);
1290
+ if (pkgJson.dependencies?.[packageName]) {
1291
+ delete pkgJson.dependencies[packageName];
1292
+ fs3.writeFileSync(pkgJsonPath, JSON.stringify(pkgJson, null, 2));
1293
+ log(`Dependency removed from package.json: ${packageName}`);
1294
+ dependencyRemoved = true;
1295
+ }
1296
+ }
1297
+ lockRemoved = removeFromBunLock(packageName);
1298
+ if (!packageRemoved && !dependencyRemoved && !lockRemoved) {
1299
+ log(`Package not found, nothing to invalidate: ${packageName}`);
1300
+ return false;
1301
+ }
1302
+ return true;
1303
+ } catch (err) {
1304
+ log("Failed to invalidate package:", err);
1305
+ return false;
1306
+ }
1307
+ }
1308
+
1309
+ // lib/hooks/auto-update/index.ts
1310
+ function createAutoUpdateHook(ctx, options = {}) {
1311
+ const { autoUpdate = true } = options;
1312
+ let hasChecked = false;
1313
+ return {
1314
+ event: async ({ event }) => {
1315
+ if (event.type !== "session.created")
1316
+ return;
1317
+ if (hasChecked)
1318
+ return;
1319
+ const props = event.properties;
1320
+ if (props?.info?.parentID)
1321
+ return;
1322
+ hasChecked = true;
1323
+ const localDevVersion = getLocalDevVersion(ctx.directory);
1324
+ if (localDevVersion) {
1325
+ log("Local development mode, skipping update check");
1326
+ return;
1327
+ }
1328
+ runBackgroundUpdateCheck(ctx, autoUpdate).catch((err) => {
1329
+ log("Background update check failed:", err);
1330
+ });
1331
+ }
1332
+ };
1333
+ }
1334
+ async function runBackgroundUpdateCheck(ctx, autoUpdate) {
1335
+ const pluginInfo = findPluginEntry(ctx.directory);
1336
+ if (!pluginInfo) {
1337
+ log("Plugin not found in config");
1338
+ return;
1339
+ }
1340
+ const cachedVersion = getCachedVersion();
1341
+ const currentVersion = cachedVersion ?? pluginInfo.pinnedVersion;
1342
+ if (!currentVersion) {
1343
+ log("No version found (cached or pinned)");
1344
+ return;
1345
+ }
1346
+ const latestVersion = await getLatestVersion();
1347
+ if (!latestVersion) {
1348
+ log("Failed to fetch latest version");
1349
+ return;
1350
+ }
1351
+ if (currentVersion === latestVersion) {
1352
+ log("Already on latest version");
1353
+ return;
1354
+ }
1355
+ log(`Update available: ${currentVersion} \u2192 ${latestVersion}`);
1356
+ if (!autoUpdate) {
1357
+ await showUpdateAvailableToast(ctx, currentVersion, latestVersion);
1358
+ log("Auto-update disabled, notification only");
1359
+ return;
1360
+ }
1361
+ if (pluginInfo.isPinned) {
1362
+ const updated = updatePinnedVersion(pluginInfo.configPath, pluginInfo.entry, latestVersion);
1363
+ if (!updated) {
1364
+ await showUpdateAvailableToast(ctx, currentVersion, latestVersion);
1365
+ log("Failed to update pinned version in config");
1366
+ return;
1367
+ }
1368
+ log(`Config updated: ${pluginInfo.entry} \u2192 ${PACKAGE_NAME}@${latestVersion}`);
1369
+ }
1370
+ invalidatePackage(PACKAGE_NAME);
1371
+ const installSuccess = await runBunInstallSafe();
1372
+ if (installSuccess) {
1373
+ await showAutoUpdatedToast(ctx, currentVersion, latestVersion);
1374
+ log(`Update installed: ${currentVersion} \u2192 ${latestVersion}`);
1375
+ } else {
1376
+ await showUpdateAvailableToast(ctx, currentVersion, latestVersion);
1377
+ log("bun install failed; update not installed (falling back to notification-only)");
1378
+ }
1379
+ }
1380
+ async function runBunInstallSafe() {
1381
+ return new Promise((resolve) => {
1382
+ try {
1383
+ const child = spawn("bun", ["install"], {
1384
+ cwd: CACHE_DIR3,
1385
+ stdio: "ignore",
1386
+ detached: true
1387
+ });
1388
+ child.unref();
1389
+ child.on("close", (code) => {
1390
+ resolve(code === 0);
1391
+ });
1392
+ child.on("error", () => {
1393
+ resolve(false);
1394
+ });
1395
+ setTimeout(() => resolve(false), 30000);
1396
+ } catch (err) {
1397
+ log("bun install error:", err);
1398
+ resolve(false);
1399
+ }
1400
+ });
1401
+ }
1402
+ async function showUpdateAvailableToast(ctx, currentVersion, latestVersion) {
1403
+ await ctx.client.tui.showToast({
1404
+ body: {
1405
+ title: `${PACKAGE_NAME} Update Available`,
1406
+ message: `v${currentVersion} \u2192 v${latestVersion}
1407
+ Restart OpenCode to apply.`,
1408
+ variant: "info",
1409
+ duration: 8000
1410
+ }
1411
+ }).catch(() => {});
1412
+ log(`Update available toast shown: v${latestVersion}`);
1413
+ }
1414
+ async function showAutoUpdatedToast(ctx, oldVersion, newVersion) {
1415
+ await ctx.client.tui.showToast({
1416
+ body: {
1417
+ title: `${PACKAGE_NAME} Updated!`,
1418
+ message: `v${oldVersion} \u2192 v${newVersion}
1419
+ Restart OpenCode to apply.`,
1420
+ variant: "success",
1421
+ duration: 8000
1422
+ }
1423
+ }).catch(() => {});
1424
+ log(`Auto-updated toast shown: v${oldVersion} \u2192 v${newVersion}`);
1425
+ }
1426
+
996
1427
  // index.ts
997
1428
  var CODEX_MODEL_PREFIXES = ["gpt-", "codex"];
998
- var PACKAGE_NAME = "opencode-aicodewith-auth";
1429
+ var PACKAGE_NAME2 = "opencode-aicodewith-auth";
999
1430
  var PROVIDER_NAME = "AICodewith";
1000
1431
  var PLUGIN_ENTRY = import.meta.url;
1001
1432
  var PROVIDER_EXT = import.meta.url.endsWith(".ts") ? ".ts" : ".js";
@@ -1003,19 +1434,20 @@ var PROVIDER_NPM = new URL(`./provider${PROVIDER_EXT}`, import.meta.url).href;
1003
1434
  var DEFAULT_API = "https://api.openai.com/v1";
1004
1435
  var DEFAULT_ENV = ["AICODEWITH_API_KEY"];
1005
1436
  var DEFAULT_OUTPUT_TOKEN_MAX = 32000;
1437
+ var IMAGE_MODALITIES = { input: ["text", "image"], output: ["text"] };
1006
1438
  var MODEL_CONFIGS = {
1007
- "gpt-5.2-codex": { name: "GPT-5.2 Codex" },
1008
- "gpt-5.2": { name: "GPT-5.2" },
1009
- "claude-sonnet-4-5-20250929": { name: "Claude Sonnet 4.5" },
1010
- "claude-opus-4-5-20251101": { name: "Claude Opus 4.5" },
1011
- "gemini-3-pro-high": { name: "Gemini 3 Pro" }
1439
+ "gpt-5.2-codex": { name: "GPT-5.2 Codex", modalities: IMAGE_MODALITIES },
1440
+ "gpt-5.2": { name: "GPT-5.2", modalities: IMAGE_MODALITIES },
1441
+ "claude-sonnet-4-5-20250929": { name: "Claude Sonnet 4.5", modalities: IMAGE_MODALITIES },
1442
+ "claude-opus-4-5-20251101": { name: "Claude Opus 4.5", modalities: IMAGE_MODALITIES },
1443
+ "gemini-3-pro-high": { name: "Gemini 3 Pro", modalities: IMAGE_MODALITIES }
1012
1444
  };
1013
1445
  var ALLOWED_MODEL_IDS = Object.keys(MODEL_CONFIGS);
1014
1446
  var ALLOWED_MODEL_SET = new Set(ALLOWED_MODEL_IDS);
1015
- var homeDir = process.env.OPENCODE_TEST_HOME || os.homedir();
1016
- var configRoot = process.env.XDG_CONFIG_HOME || path.join(homeDir, ".config");
1017
- var configDir = path.join(configRoot, "opencode");
1018
- var configPath = path.join(configDir, "opencode.json");
1447
+ var homeDir = process.env.OPENCODE_TEST_HOME || os3.homedir();
1448
+ var configRoot = process.env.XDG_CONFIG_HOME || path4.join(homeDir, ".config");
1449
+ var configDir = path4.join(configRoot, "opencode");
1450
+ var configPath = path4.join(configDir, "opencode.json");
1019
1451
  var ensureConfigPromise;
1020
1452
  var toModelMap = (ids, existing = {}) => ids.reduce((acc, id) => {
1021
1453
  const existingConfig = Object.prototype.hasOwnProperty.call(existing, id) ? existing[id] : {};
@@ -1031,7 +1463,7 @@ var readJson = async (filePath) => {
1031
1463
  return;
1032
1464
  }
1033
1465
  };
1034
- var isPackageEntry = (value) => value === PACKAGE_NAME || value.startsWith(`${PACKAGE_NAME}@`);
1466
+ var isPackageEntry = (value) => value === PACKAGE_NAME2 || value.startsWith(`${PACKAGE_NAME2}@`);
1035
1467
  var ensurePluginEntry = (list) => {
1036
1468
  if (!Array.isArray(list))
1037
1469
  return [PLUGIN_ENTRY];
@@ -1145,14 +1577,14 @@ var ensureGeminiSseParam = (url) => {
1145
1577
  };
1146
1578
  var buildGeminiUrl = (originalUrl, streaming) => {
1147
1579
  const original = new URL(originalUrl);
1148
- let path2 = original.pathname;
1149
- if (!path2.includes("/v1beta/") && !path2.includes("/v1/")) {
1150
- path2 = `/v1beta${path2.startsWith("/") ? "" : "/"}${path2}`;
1580
+ let path5 = original.pathname;
1581
+ if (!path5.includes("/v1beta/") && !path5.includes("/v1/")) {
1582
+ path5 = `/v1beta${path5.startsWith("/") ? "" : "/"}${path5}`;
1151
1583
  }
1152
1584
  const base = new URL(AICODEWITH_GEMINI_BASE_URL);
1153
1585
  const basePath = base.pathname.replace(/\/$/, "");
1154
1586
  const target = new URL(base.origin);
1155
- target.pathname = `${basePath}${path2}`;
1587
+ target.pathname = `${basePath}${path5}`;
1156
1588
  target.search = original.search;
1157
1589
  const url = target.toString();
1158
1590
  return streaming ? ensureGeminiSseParam(url) : url;
@@ -1187,10 +1619,11 @@ var getOutputTokenLimit = (input, output) => {
1187
1619
  }
1188
1620
  return DEFAULT_OUTPUT_TOKEN_MAX;
1189
1621
  };
1190
- var AicodewithCodexAuthPlugin = async (_ctx) => {
1622
+ var AicodewithCodexAuthPlugin = async (ctx) => {
1191
1623
  await ensureConfigFile().catch((error) => {
1192
- console.warn(`[${PACKAGE_NAME}] Failed to update opencode config: ${error instanceof Error ? error.message : error}`);
1624
+ console.warn(`[${PACKAGE_NAME2}] Failed to update opencode config: ${error instanceof Error ? error.message : error}`);
1193
1625
  });
1626
+ const autoUpdateHook = createAutoUpdateHook(ctx, { autoUpdate: true });
1194
1627
  const authHook = {
1195
1628
  provider: PROVIDER_ID,
1196
1629
  loader: async (getAuth, _provider) => {
@@ -1266,6 +1699,7 @@ var AicodewithCodexAuthPlugin = async (_ctx) => {
1266
1699
  config: async (config) => {
1267
1700
  applyProviderConfig(config);
1268
1701
  },
1702
+ event: autoUpdateHook.event,
1269
1703
  "chat.params": async (input, output) => {
1270
1704
  if (input.model.providerID !== PROVIDER_ID)
1271
1705
  return;
@@ -0,0 +1 @@
1
+ export declare function invalidatePackage(packageName?: string): boolean;
@@ -0,0 +1,10 @@
1
+ import type { PluginEntryInfo } from "./types";
2
+ declare function log(...args: unknown[]): void;
3
+ export declare function isLocalDevMode(directory: string): boolean;
4
+ export declare function getLocalDevPath(directory: string): string | null;
5
+ export declare function getLocalDevVersion(directory: string): string | null;
6
+ export declare function findPluginEntry(directory: string): PluginEntryInfo | null;
7
+ export declare function getCachedVersion(): string | null;
8
+ export declare function updatePinnedVersion(configPath: string, oldEntry: string, newVersion: string): boolean;
9
+ export declare function getLatestVersion(): Promise<string | null>;
10
+ export { log };
@@ -0,0 +1,15 @@
1
+ /**
2
+ * @file constants.ts
3
+ * @input None
4
+ * @output Auto-update configuration constants
5
+ * @pos Constants for package paths, npm registry, cache directories
6
+ */
7
+ export declare const PACKAGE_NAME = "opencode-aicodewith-auth";
8
+ export declare const NPM_REGISTRY_URL = "https://registry.npmjs.org/-/package/opencode-aicodewith-auth/dist-tags";
9
+ export declare const NPM_FETCH_TIMEOUT = 5000;
10
+ export declare const CACHE_DIR: string;
11
+ export declare const INSTALLED_PACKAGE_JSON: string;
12
+ export declare function getWindowsAppdataDir(): string | null;
13
+ export declare const USER_CONFIG_DIR: string;
14
+ export declare const USER_OPENCODE_CONFIG: string;
15
+ export declare const USER_OPENCODE_CONFIG_JSONC: string;
@@ -0,0 +1,12 @@
1
+ import type { PluginInput } from "@opencode-ai/plugin";
2
+ import type { AutoUpdateOptions } from "./types";
3
+ export declare function createAutoUpdateHook(ctx: PluginInput, options?: AutoUpdateOptions): {
4
+ event: ({ event }: {
5
+ event: {
6
+ type: string;
7
+ properties?: unknown;
8
+ };
9
+ }) => Promise<void>;
10
+ };
11
+ export type { AutoUpdateOptions } from "./types";
12
+ export { invalidatePackage } from "./cache";
@@ -0,0 +1,29 @@
1
+ export interface NpmDistTags {
2
+ latest: string;
3
+ [key: string]: string;
4
+ }
5
+ export interface OpencodeConfig {
6
+ plugin?: string[];
7
+ [key: string]: unknown;
8
+ }
9
+ export interface PackageJson {
10
+ version: string;
11
+ name?: string;
12
+ [key: string]: unknown;
13
+ }
14
+ export interface UpdateCheckResult {
15
+ needsUpdate: boolean;
16
+ currentVersion: string | null;
17
+ latestVersion: string | null;
18
+ isLocalDev: boolean;
19
+ isPinned: boolean;
20
+ }
21
+ export interface AutoUpdateOptions {
22
+ autoUpdate?: boolean;
23
+ }
24
+ export interface PluginEntryInfo {
25
+ entry: string;
26
+ isPinned: boolean;
27
+ pinnedVersion: string | null;
28
+ configPath: string;
29
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-aicodewith-auth",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "OpenCode plugin for AICodewith authentication - Access GPT-5.2, Claude, and Gemini models through AICodewith API",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",