@anthonyhaussman/opencode-agy-auth 1.2.3-alpha.3 → 1.2.3-alpha.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/dist/index.js CHANGED
@@ -104,6 +104,8 @@ function updateStaticModelsWithPricing(staticModels) {
104
104
 
105
105
  // src/constants.ts
106
106
  var AGY_PROVIDER_ID = "google-agy";
107
+ var AGY_AUTH_URL = "https://accounts.google.com/o/oauth2/auth";
108
+ var AGY_TOKEN_URL = "https://oauth2.googleapis.com/token";
107
109
  var AGY_CLIENT_ID = "1071006060591-tmhssin2h21lcre235vtolojh4g403ep.apps.googleusercontent.com";
108
110
  var AGY_CLIENT_SECRET = "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";
109
111
  var AGY_SCOPES = [
@@ -20664,6 +20666,9 @@ function defineOpenCodeV2Plugin(def) {
20664
20666
  }
20665
20667
 
20666
20668
  // src/plugin/v2.ts
20669
+ import { homedir as homedir4 } from "os";
20670
+ import { join as join6 } from "path";
20671
+ import { existsSync as existsSync6, readFileSync as readFileSync5 } from "fs";
20667
20672
  var AGY_V2_QUOTA_COMMAND = "agy-quota";
20668
20673
  var AGY_V2_QUOTA_SUMMARY_COMMAND = "agy-quota-summary";
20669
20674
  var AGY_V2_QUOTA_COMMAND_TEMPLATE = `Retrieve Agy Code Assist quota usage for the current authenticated account.
@@ -20676,6 +20681,203 @@ var AGY_V2_QUOTA_SUMMARY_COMMAND_TEMPLATE = `Retrieve Agy Code Assist quota summ
20676
20681
  Immediately call \`${AGY_QUOTA_SUMMARY_TOOL_NAME}\` with no arguments and return its output verbatim.
20677
20682
  Do not call other tools.
20678
20683
  `;
20684
+ function getSafeHeader2(headers, key) {
20685
+ if (!headers) {
20686
+ return void 0;
20687
+ }
20688
+ const targetKey = key.toLowerCase();
20689
+ if (typeof headers.get === "function") {
20690
+ try {
20691
+ return headers.get(targetKey) || void 0;
20692
+ } catch {
20693
+ }
20694
+ }
20695
+ if (Array.isArray(headers)) {
20696
+ const found = headers.find((item) => {
20697
+ if (Array.isArray(item) && typeof item[0] === "string") {
20698
+ return item[0].toLowerCase() === targetKey;
20699
+ }
20700
+ return false;
20701
+ });
20702
+ return found ? String(found[1]) : void 0;
20703
+ }
20704
+ if (typeof headers === "object") {
20705
+ const foundKey = Object.keys(headers).find((k) => k.toLowerCase() === targetKey);
20706
+ return foundKey ? headers[foundKey] !== void 0 ? String(headers[foundKey]) : void 0 : void 0;
20707
+ }
20708
+ return void 0;
20709
+ }
20710
+ function setSafeHeaders2(initHeaders, newHeaders) {
20711
+ if (typeof globalThis.Headers !== "undefined") {
20712
+ const headers = new globalThis.Headers(initHeaders ?? {});
20713
+ for (const [k, v] of Object.entries(newHeaders)) {
20714
+ headers.set(k, v);
20715
+ }
20716
+ return headers;
20717
+ }
20718
+ if (Array.isArray(initHeaders)) {
20719
+ const nextHeaders2 = [...initHeaders];
20720
+ for (const [k, v] of Object.entries(newHeaders)) {
20721
+ const idx = nextHeaders2.findIndex((item) => Array.isArray(item) && typeof item[0] === "string" && item[0].toLowerCase() === k.toLowerCase());
20722
+ if (idx !== -1) {
20723
+ nextHeaders2[idx] = [k, v];
20724
+ } else {
20725
+ nextHeaders2.push([k, v]);
20726
+ }
20727
+ }
20728
+ return nextHeaders2;
20729
+ }
20730
+ const nextHeaders = {};
20731
+ if (initHeaders && typeof initHeaders === "object") {
20732
+ for (const [k, v] of Object.entries(initHeaders)) {
20733
+ nextHeaders[k] = String(v);
20734
+ }
20735
+ }
20736
+ for (const [k, v] of Object.entries(newHeaders)) {
20737
+ const existingKey = Object.keys(nextHeaders).find((key) => key.toLowerCase() === k.toLowerCase());
20738
+ if (existingKey) {
20739
+ nextHeaders[existingKey] = v;
20740
+ } else {
20741
+ nextHeaders[k] = v;
20742
+ }
20743
+ }
20744
+ return nextHeaders;
20745
+ }
20746
+ function toUrlString2(value) {
20747
+ if (typeof value === "string") {
20748
+ return value;
20749
+ }
20750
+ const candidate = value.url;
20751
+ if (candidate) {
20752
+ return candidate;
20753
+ }
20754
+ return value.toString();
20755
+ }
20756
+ function resolveModelTier2(baseModelId, init) {
20757
+ const parts = baseModelId.split("@");
20758
+ const base = parts[0] || "";
20759
+ const suffixTier = parts[1]?.toLowerCase();
20760
+ const mapping = TIER_MAPPING[base];
20761
+ if (!mapping) {
20762
+ return baseModelId;
20763
+ }
20764
+ const headerTier = getSafeHeader2(init?.headers, "x-agy-tier")?.toLowerCase() || null;
20765
+ const requestedTier = headerTier || suffixTier;
20766
+ if (requestedTier && Object.prototype.hasOwnProperty.call(mapping, requestedTier)) {
20767
+ return mapping[requestedTier] || baseModelId;
20768
+ }
20769
+ return mapping["medium"] ?? mapping["high"];
20770
+ }
20771
+ function loadStoredAuthFromJson() {
20772
+ const authPath = join6(homedir4(), ".local", "share", "opencode", "auth.json");
20773
+ try {
20774
+ if (existsSync6(authPath)) {
20775
+ const content = readFileSync5(authPath, "utf8");
20776
+ const data = JSON.parse(content);
20777
+ return data?.[AGY_PROVIDER_ID];
20778
+ }
20779
+ } catch {
20780
+ }
20781
+ return void 0;
20782
+ }
20783
+ function createV2FetchInterceptor(getAuthSnapshot) {
20784
+ return async function agyV2Fetch(input, init) {
20785
+ const isGL = isGenerativeLanguageRequest(input);
20786
+ const isInternal = toUrlString2(input).includes("cloudcode-pa.googleapis.com");
20787
+ if (!isGL && !isInternal) {
20788
+ return agyFetch(input, init);
20789
+ }
20790
+ let rawAuth = getAuthSnapshot ? await getAuthSnapshot() : void 0;
20791
+ if (!rawAuth) {
20792
+ rawAuth = loadStoredAuthFromJson();
20793
+ }
20794
+ if (!rawAuth || !isOAuthAuth(rawAuth)) {
20795
+ return agyFetch(input, init);
20796
+ }
20797
+ let authRecord = resolveCachedAuth(rawAuth);
20798
+ if (accessTokenExpired(authRecord)) {
20799
+ const refreshed = await refreshAccessToken(authRecord, { auth: { set: async () => {
20800
+ } } });
20801
+ if (refreshed) {
20802
+ authRecord = refreshed;
20803
+ }
20804
+ }
20805
+ if (!authRecord.access) {
20806
+ return agyFetch(input, init);
20807
+ }
20808
+ if (isInternal) {
20809
+ const hasAuth = getSafeHeader2(init?.headers, "Authorization") !== void 0;
20810
+ if (hasAuth) {
20811
+ return agyFetch(input, init);
20812
+ }
20813
+ const userAgent = buildAgyCliUserAgent();
20814
+ const headers = setSafeHeaders2(init?.headers, {
20815
+ Authorization: `Bearer ${authRecord.access}`,
20816
+ "User-Agent": userAgent
20817
+ });
20818
+ return agyFetch(input, {
20819
+ ...init,
20820
+ headers
20821
+ });
20822
+ }
20823
+ const requestTarget = parseGenerativeLanguageRequest(input);
20824
+ const requestUserAgentModel = requestTarget?.effectiveModel;
20825
+ let projectContext;
20826
+ try {
20827
+ projectContext = await ensureProjectContext(
20828
+ authRecord,
20829
+ { auth: { set: async () => {
20830
+ } } },
20831
+ void 0,
20832
+ requestUserAgentModel
20833
+ );
20834
+ } catch {
20835
+ projectContext = {
20836
+ effectiveProjectId: parseRefreshParts(authRecord.refresh).projectId || "antigravity",
20837
+ auth: authRecord
20838
+ };
20839
+ }
20840
+ const originalRequestedModel = parseGenerativeLanguageRequest(input)?.effectiveModel;
20841
+ let modifiedInput = input;
20842
+ if (isGL && originalRequestedModel) {
20843
+ const originalBase = originalRequestedModel.replace("google-agy/", "");
20844
+ const resolvedBase = resolveModelTier2(originalBase, init);
20845
+ if (originalBase !== resolvedBase) {
20846
+ if (typeof modifiedInput === "string") {
20847
+ modifiedInput = modifiedInput.replace(`models/${originalBase}`, `models/${resolvedBase}`);
20848
+ } else if (typeof Request !== "undefined" && modifiedInput instanceof Request) {
20849
+ const newUrl = modifiedInput.url.replace(`models/${originalBase}`, `models/${resolvedBase}`);
20850
+ modifiedInput = new Request(newUrl, modifiedInput);
20851
+ }
20852
+ }
20853
+ }
20854
+ const transformed = prepareAgyRequest(
20855
+ modifiedInput,
20856
+ init,
20857
+ authRecord.access,
20858
+ projectContext.effectiveProjectId,
20859
+ void 0
20860
+ );
20861
+ const chatLogger = createChatLogger();
20862
+ if (chatLogger) {
20863
+ chatLogger.logRequest(
20864
+ toUrlString2(transformed.request),
20865
+ transformed.init.method || "GET",
20866
+ transformed.init.headers,
20867
+ transformed.init.body
20868
+ );
20869
+ }
20870
+ const response = await fetchWithRetry(transformed.request, transformed.init);
20871
+ return transformAgyResponse(
20872
+ response,
20873
+ transformed.streaming,
20874
+ null,
20875
+ transformed.requestedModel,
20876
+ transformed.sessionId,
20877
+ chatLogger
20878
+ );
20879
+ };
20880
+ }
20679
20881
  async function setupOpenCodeV2(ctx) {
20680
20882
  ctx.catalog.transform(async (editor) => {
20681
20883
  if (!editor) return;
@@ -20853,14 +21055,85 @@ async function setupOpenCodeV2(ctx) {
20853
21055
  label: "Antigravity CLI (OAuth)"
20854
21056
  },
20855
21057
  authorize: async () => {
21058
+ const authUrl = new URL(AGY_AUTH_URL);
21059
+ authUrl.searchParams.set("client_id", AGY_CLIENT_ID);
21060
+ authUrl.searchParams.set("response_type", "code");
21061
+ authUrl.searchParams.set("redirect_uri", "http://localhost");
21062
+ authUrl.searchParams.set("scope", AGY_SCOPES.join(" "));
21063
+ authUrl.searchParams.set("access_type", "offline");
21064
+ authUrl.searchParams.set("prompt", "consent");
20856
21065
  return {
20857
- mode: "auto",
20858
- url: "https://accounts.google.com/o/oauth2/auth",
20859
- instructions: "Login with Google Cloud / Antigravity CLI credentials"
21066
+ mode: "code",
21067
+ url: authUrl.toString(),
21068
+ instructions: "Please complete Google account authorization in your browser. After authorization, copy the full redirect URL or code and paste it below:",
21069
+ callback: async (code) => {
21070
+ const trimmed = code.trim();
21071
+ const parsed = parseOAuthCallbackInput(trimmed);
21072
+ const authCode = parsed.code || trimmed;
21073
+ if (!authCode) {
21074
+ return { type: "failed", error: "Missing authorization code in callback input" };
21075
+ }
21076
+ const tokenResponse = await agyFetch(AGY_TOKEN_URL, {
21077
+ method: "POST",
21078
+ headers: {
21079
+ "Content-Type": "application/x-www-form-urlencoded"
21080
+ },
21081
+ body: new URLSearchParams({
21082
+ client_id: AGY_CLIENT_ID,
21083
+ client_secret: AGY_CLIENT_SECRET,
21084
+ code: authCode,
21085
+ grant_type: "authorization_code",
21086
+ redirect_uri: "http://localhost"
21087
+ })
21088
+ });
21089
+ if (!tokenResponse.ok) {
21090
+ const errorText = await tokenResponse.text();
21091
+ return { type: "failed", error: errorText };
21092
+ }
21093
+ const tokenPayload = await tokenResponse.json();
21094
+ if (!tokenPayload.refresh_token) {
21095
+ return { type: "failed", error: "Missing refresh token in response" };
21096
+ }
21097
+ const initialRefresh = formatRefreshParts({
21098
+ refreshToken: tokenPayload.refresh_token
21099
+ });
21100
+ let authRecord = {
21101
+ type: "oauth",
21102
+ refresh: initialRefresh,
21103
+ access: tokenPayload.access_token,
21104
+ expires: Date.now() + tokenPayload.expires_in * 1e3
21105
+ };
21106
+ try {
21107
+ const projectContext = await ensureProjectContext(
21108
+ authRecord,
21109
+ { auth: { set: async () => {
21110
+ } } }
21111
+ );
21112
+ authRecord = {
21113
+ ...authRecord,
21114
+ refresh: projectContext.auth.refresh
21115
+ };
21116
+ } catch {
21117
+ }
21118
+ return {
21119
+ type: "success",
21120
+ refresh: authRecord.refresh,
21121
+ access: authRecord.access,
21122
+ expires: authRecord.expires
21123
+ };
21124
+ }
20860
21125
  };
20861
21126
  }
20862
21127
  });
20863
21128
  });
21129
+ ctx.aisdk?.hook("sdk", async (event) => {
21130
+ if (!event) return;
21131
+ const isMatchingProvider = event.providerID === AGY_PROVIDER_ID || event.model?.providerID === AGY_PROVIDER_ID;
21132
+ if (!isMatchingProvider) return;
21133
+ event.options = event.options || {};
21134
+ event.options.apiKey = "dummy";
21135
+ event.options.fetch = createV2FetchInterceptor();
21136
+ });
20864
21137
  ctx.session.hook(
20865
21138
  "http.request",
20866
21139
  async (event) => {