opencode-aicodewith-auth 0.1.4 → 0.1.8

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/dist/index.js CHANGED
@@ -59,7 +59,7 @@ function createAicodewith(options = {}) {
59
59
  var aicodewith = createAicodewith();
60
60
 
61
61
  // index.ts
62
- import { mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
62
+ import { mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2, access } from "fs/promises";
63
63
  import path4 from "path";
64
64
  import os3 from "os";
65
65
 
@@ -1307,8 +1307,10 @@ function invalidatePackage(packageName = PACKAGE_NAME) {
1307
1307
  }
1308
1308
 
1309
1309
  // lib/hooks/auto-update/index.ts
1310
+ var DISPLAY_NAME = "AICodewith";
1311
+ var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
1310
1312
  function createAutoUpdateHook(ctx, options = {}) {
1311
- const { autoUpdate = true } = options;
1313
+ const { autoUpdate = true, showStartupToast = true } = options;
1312
1314
  let hasChecked = false;
1313
1315
  return {
1314
1316
  event: async ({ event }) => {
@@ -1320,17 +1322,43 @@ function createAutoUpdateHook(ctx, options = {}) {
1320
1322
  if (props?.info?.parentID)
1321
1323
  return;
1322
1324
  hasChecked = true;
1325
+ const cachedVersion = getCachedVersion();
1323
1326
  const localDevVersion = getLocalDevVersion(ctx.directory);
1327
+ const displayVersion = localDevVersion ?? cachedVersion ?? "unknown";
1324
1328
  if (localDevVersion) {
1329
+ if (showStartupToast) {
1330
+ showStartupToastWithSpinner(ctx, `${displayVersion} (dev)`, "Local development mode").catch(() => {});
1331
+ }
1325
1332
  log("Local development mode, skipping update check");
1326
1333
  return;
1327
1334
  }
1335
+ if (showStartupToast) {
1336
+ showStartupToastWithSpinner(ctx, displayVersion, "GPT-5.2 \xB7 Claude \xB7 Gemini").catch(() => {});
1337
+ }
1328
1338
  runBackgroundUpdateCheck(ctx, autoUpdate).catch((err) => {
1329
1339
  log("Background update check failed:", err);
1330
1340
  });
1331
1341
  }
1332
1342
  };
1333
1343
  }
1344
+ async function showStartupToastWithSpinner(ctx, version, message) {
1345
+ const totalDuration = 3000;
1346
+ const frameInterval = 100;
1347
+ const totalFrames = Math.floor(totalDuration / frameInterval);
1348
+ for (let i = 0;i < totalFrames; i++) {
1349
+ const spinner = SPINNER_FRAMES[i % SPINNER_FRAMES.length];
1350
+ await ctx.client.tui.showToast({
1351
+ body: {
1352
+ title: `${spinner} ${DISPLAY_NAME} v${version}`,
1353
+ message,
1354
+ variant: "info",
1355
+ duration: frameInterval + 50
1356
+ }
1357
+ }).catch(() => {});
1358
+ await new Promise((resolve) => setTimeout(resolve, frameInterval));
1359
+ }
1360
+ log(`Startup toast shown: v${version}`);
1361
+ }
1334
1362
  async function runBackgroundUpdateCheck(ctx, autoUpdate) {
1335
1363
  const pluginInfo = findPluginEntry(ctx.directory);
1336
1364
  if (!pluginInfo) {
@@ -1402,7 +1430,7 @@ async function runBunInstallSafe() {
1402
1430
  async function showUpdateAvailableToast(ctx, currentVersion, latestVersion) {
1403
1431
  await ctx.client.tui.showToast({
1404
1432
  body: {
1405
- title: `${PACKAGE_NAME} Update Available`,
1433
+ title: `${DISPLAY_NAME} Update Available`,
1406
1434
  message: `v${currentVersion} \u2192 v${latestVersion}
1407
1435
  Restart OpenCode to apply.`,
1408
1436
  variant: "info",
@@ -1414,7 +1442,7 @@ Restart OpenCode to apply.`,
1414
1442
  async function showAutoUpdatedToast(ctx, oldVersion, newVersion) {
1415
1443
  await ctx.client.tui.showToast({
1416
1444
  body: {
1417
- title: `${PACKAGE_NAME} Updated!`,
1445
+ title: `${DISPLAY_NAME} Updated!`,
1418
1446
  message: `v${oldVersion} \u2192 v${newVersion}
1419
1447
  Restart OpenCode to apply.`,
1420
1448
  variant: "success",
@@ -1423,46 +1451,91 @@ Restart OpenCode to apply.`,
1423
1451
  }).catch(() => {});
1424
1452
  log(`Auto-updated toast shown: v${oldVersion} \u2192 v${newVersion}`);
1425
1453
  }
1454
+ // lib/provider-config.json
1455
+ var provider_config_default = {
1456
+ name: "AICodewith",
1457
+ env: ["AICODEWITH_API_KEY"],
1458
+ api: "https://api.openai.com/v1",
1459
+ models: {
1460
+ "gpt-5.2-codex": {
1461
+ name: "GPT-5.2 Codex",
1462
+ modalities: { input: ["text", "image"], output: ["text"] }
1463
+ },
1464
+ "gpt-5.2": {
1465
+ name: "GPT-5.2",
1466
+ modalities: { input: ["text", "image"], output: ["text"] }
1467
+ },
1468
+ "claude-sonnet-4-5-20250929": {
1469
+ name: "Claude Sonnet 4.5",
1470
+ modalities: { input: ["text", "image"], output: ["text"] }
1471
+ },
1472
+ "claude-opus-4-5-20251101": {
1473
+ name: "Claude Opus 4.5",
1474
+ modalities: { input: ["text", "image"], output: ["text"] }
1475
+ },
1476
+ "gemini-3-pro-high": {
1477
+ name: "Gemini 3 Pro",
1478
+ modalities: { input: ["text", "image"], output: ["text"] }
1479
+ }
1480
+ }
1481
+ };
1426
1482
 
1427
1483
  // index.ts
1428
1484
  var CODEX_MODEL_PREFIXES = ["gpt-", "codex"];
1429
1485
  var PACKAGE_NAME2 = "opencode-aicodewith-auth";
1430
- var PROVIDER_NAME = "AICodewith";
1431
1486
  var PLUGIN_ENTRY = import.meta.url;
1432
1487
  var PROVIDER_EXT = import.meta.url.endsWith(".ts") ? ".ts" : ".js";
1433
1488
  var PROVIDER_NPM = new URL(`./provider${PROVIDER_EXT}`, import.meta.url).href;
1434
- var DEFAULT_API = "https://api.openai.com/v1";
1435
- var DEFAULT_ENV = ["AICODEWITH_API_KEY"];
1436
1489
  var DEFAULT_OUTPUT_TOKEN_MAX = 32000;
1437
- var IMAGE_MODALITIES = { input: ["text", "image"], output: ["text"] };
1438
- var MODEL_CONFIGS = {
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 }
1444
- };
1445
- var ALLOWED_MODEL_IDS = Object.keys(MODEL_CONFIGS);
1446
- var ALLOWED_MODEL_SET = new Set(ALLOWED_MODEL_IDS);
1447
1490
  var homeDir = process.env.OPENCODE_TEST_HOME || os3.homedir();
1448
1491
  var configRoot = process.env.XDG_CONFIG_HOME || path4.join(homeDir, ".config");
1449
1492
  var configDir = path4.join(configRoot, "opencode");
1450
- var configPath = path4.join(configDir, "opencode.json");
1493
+ var configPathJson = path4.join(configDir, "opencode.json");
1494
+ var configPathJsonc = path4.join(configDir, "opencode.jsonc");
1451
1495
  var ensureConfigPromise;
1452
- var toModelMap = (ids, existing = {}) => ids.reduce((acc, id) => {
1453
- const existingConfig = Object.prototype.hasOwnProperty.call(existing, id) ? existing[id] : {};
1454
- const defaultConfig = MODEL_CONFIGS[id] ?? {};
1455
- acc[id] = { ...defaultConfig, ...typeof existingConfig === "object" ? existingConfig : {} };
1456
- return acc;
1457
- }, {});
1458
- var readJson = async (filePath) => {
1496
+ var fileExists = async (filePath) => {
1497
+ try {
1498
+ await access(filePath);
1499
+ return true;
1500
+ } catch {
1501
+ return false;
1502
+ }
1503
+ };
1504
+ var stripJsonComments2 = (content) => {
1505
+ return content.replace(/\\"|"(?:\\"|[^"])*"|(\/\/.*|\/\*[\s\S]*?\*\/)/g, (m, g) => g ? "" : m).replace(/,(\s*[}\]])/g, "$1");
1506
+ };
1507
+ var readJsonOrJsonc = async (filePath) => {
1459
1508
  try {
1460
1509
  const text = await readFile2(filePath, "utf-8");
1461
- return JSON.parse(text);
1510
+ const stripped = filePath.endsWith(".jsonc") ? stripJsonComments2(text) : text;
1511
+ return JSON.parse(stripped);
1462
1512
  } catch {
1463
1513
  return;
1464
1514
  }
1465
1515
  };
1516
+ var deepEqual = (a, b) => {
1517
+ if (a === b)
1518
+ return true;
1519
+ if (typeof a !== typeof b)
1520
+ return false;
1521
+ if (a === null || b === null)
1522
+ return a === b;
1523
+ if (typeof a !== "object")
1524
+ return false;
1525
+ const aObj = a;
1526
+ const bObj = b;
1527
+ const aKeys = Object.keys(aObj);
1528
+ const bKeys = Object.keys(bObj);
1529
+ if (aKeys.length !== bKeys.length)
1530
+ return false;
1531
+ for (const key of aKeys) {
1532
+ if (!Object.prototype.hasOwnProperty.call(bObj, key))
1533
+ return false;
1534
+ if (!deepEqual(aObj[key], bObj[key]))
1535
+ return false;
1536
+ }
1537
+ return true;
1538
+ };
1466
1539
  var isPackageEntry = (value) => value === PACKAGE_NAME2 || value.startsWith(`${PACKAGE_NAME2}@`);
1467
1540
  var ensurePluginEntry = (list) => {
1468
1541
  if (!Array.isArray(list))
@@ -1470,36 +1543,17 @@ var ensurePluginEntry = (list) => {
1470
1543
  const hasPlugin = list.some((entry) => typeof entry === "string" && (entry === PLUGIN_ENTRY || isPackageEntry(entry)));
1471
1544
  return hasPlugin ? list : [...list, PLUGIN_ENTRY];
1472
1545
  };
1546
+ var buildStandardProviderConfig = () => ({
1547
+ ...provider_config_default,
1548
+ npm: PROVIDER_NPM
1549
+ });
1473
1550
  var applyProviderConfig = (config) => {
1474
1551
  let changed = false;
1475
1552
  const providerMap = config.provider && typeof config.provider === "object" ? config.provider : {};
1476
- const existing = providerMap[PROVIDER_ID] && typeof providerMap[PROVIDER_ID] === "object" ? providerMap[PROVIDER_ID] : {};
1477
- const existingModels = existing.models && typeof existing.models === "object" ? existing.models : {};
1478
- const next = { ...existing };
1479
- if (!next.name) {
1480
- next.name = PROVIDER_NAME;
1481
- changed = true;
1482
- }
1483
- if (!Array.isArray(next.env)) {
1484
- next.env = DEFAULT_ENV;
1485
- changed = true;
1486
- }
1487
- if (!next.npm || typeof next.npm === "string" && isPackageEntry(next.npm)) {
1488
- next.npm = PROVIDER_NPM;
1489
- changed = true;
1490
- }
1491
- if (!next.api) {
1492
- next.api = DEFAULT_API;
1493
- changed = true;
1494
- }
1495
- const hasExtraModels = Object.keys(existingModels).some((id) => !ALLOWED_MODEL_SET.has(id));
1496
- const hasMissingModels = ALLOWED_MODEL_IDS.some((id) => !Object.prototype.hasOwnProperty.call(existingModels, id));
1497
- if (!next.models || hasExtraModels || hasMissingModels) {
1498
- next.models = toModelMap(ALLOWED_MODEL_IDS, existingModels);
1499
- changed = true;
1500
- }
1501
- providerMap[PROVIDER_ID] = next;
1502
- if (config.provider !== providerMap) {
1553
+ const existingProvider = providerMap[PROVIDER_ID];
1554
+ const standardProvider = buildStandardProviderConfig();
1555
+ if (!deepEqual(existingProvider, standardProvider)) {
1556
+ providerMap[PROVIDER_ID] = standardProvider;
1503
1557
  config.provider = providerMap;
1504
1558
  changed = true;
1505
1559
  }
@@ -1514,7 +1568,20 @@ var ensureConfigFile = async () => {
1514
1568
  if (ensureConfigPromise)
1515
1569
  return ensureConfigPromise;
1516
1570
  ensureConfigPromise = (async () => {
1517
- const config = await readJson(configPath) ?? {};
1571
+ const jsoncExists = await fileExists(configPathJsonc);
1572
+ const jsonExists = await fileExists(configPathJson);
1573
+ let configPath;
1574
+ let config;
1575
+ if (jsoncExists) {
1576
+ configPath = configPathJsonc;
1577
+ config = await readJsonOrJsonc(configPath) ?? {};
1578
+ } else if (jsonExists) {
1579
+ configPath = configPathJson;
1580
+ config = await readJsonOrJsonc(configPath) ?? {};
1581
+ } else {
1582
+ configPath = configPathJson;
1583
+ config = { $schema: "https://opencode.ai/config.json" };
1584
+ }
1518
1585
  if (!config || typeof config !== "object")
1519
1586
  return;
1520
1587
  const changed = applyProviderConfig(config);
@@ -20,6 +20,7 @@ export interface UpdateCheckResult {
20
20
  }
21
21
  export interface AutoUpdateOptions {
22
22
  autoUpdate?: boolean;
23
+ showStartupToast?: boolean;
23
24
  }
24
25
  export interface PluginEntryInfo {
25
26
  entry: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-aicodewith-auth",
3
- "version": "0.1.4",
3
+ "version": "0.1.8",
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",