// Force strict mode and setup for ESM
"use strict";
const __papertOriginalEmitWarning = process.emitWarning.bind(process);
process.emitWarning = function patchedEmitWarning(warning, ...args) {
  if (!process.env.PAPERT_SHOW_NODE_DEPRECATIONS) {
    const warningCode =
      (warning && typeof warning === 'object' && 'code' in warning && warning.code) ||
      (args.length > 1 && typeof args[1] === 'string' && args[1]) ||
      (args.length > 0 &&
        args[0] &&
        typeof args[0] === 'object' &&
        'code' in args[0] &&
        args[0].code);
    if (warningCode === 'DEP0040' || warningCode === 'DEP0169') {
      return;
    }
  }
  return __papertOriginalEmitWarning(warning, ...args);
};
import {
  isNodeError,
  open_default
} from "./chunk-4YLWLT76.js";
import {
  __name,
  init_esbuild_shims
} from "./chunk-NCFEMX7E.js";

// packages/core/dist/src/papert/papertOAuth2.js
init_esbuild_shims();
import crypto2 from "crypto";
import path3 from "node:path";
import { promises as fs3 } from "node:fs";
import * as os3 from "os";
import { EventEmitter } from "events";

// packages/core/dist/src/utils/paths.js
init_esbuild_shims();
import fs from "node:fs";
import path from "node:path";
import os from "node:os";
import * as crypto from "node:crypto";
var PAPERT_DIR = ".papert";
var PAPERT_CREDENTIAL_FILENAME = "oauth_creds.json";
var PAPERT_LOCK_FILENAME = "oauth_creds.lock";
var SHELL_SPECIAL_CHARS = /[ \t()[\]{};|*?$`'"#&<>!~]/;
function tildeifyPath(path4) {
  const homeDir = os.homedir();
  if (path4.startsWith(homeDir)) {
    return path4.replace(homeDir, "~");
  }
  return path4;
}
__name(tildeifyPath, "tildeifyPath");
function shortenPath(filePath, maxLen = 80) {
  if (filePath.length <= maxLen) {
    return filePath;
  }
  const parsedPath = path.parse(filePath);
  const root = parsedPath.root;
  const separator = path.sep;
  const relativePath = filePath.substring(root.length);
  const segments = relativePath.split(separator).filter((s) => s !== "");
  if (segments.length <= 1) {
    const keepLen = Math.floor((maxLen - 3) / 2);
    if (keepLen <= 0) {
      return filePath.substring(0, maxLen - 3) + "...";
    }
    const start = filePath.substring(0, keepLen);
    const end = filePath.substring(filePath.length - keepLen);
    return `${start}...${end}`;
  }
  const firstDir = segments[0];
  const lastSegment = segments[segments.length - 1];
  const startComponent = root + firstDir;
  const endPartSegments = [];
  let currentLength = separator.length + lastSegment.length;
  for (let i = segments.length - 2; i >= 0; i--) {
    const segment = segments[i];
    const lengthWithSegment = currentLength + separator.length + segment.length;
    if (lengthWithSegment <= maxLen) {
      endPartSegments.unshift(segment);
      currentLength = lengthWithSegment;
    } else {
      break;
    }
  }
  let result = endPartSegments.join(separator) + separator + lastSegment;
  if (currentLength > maxLen) {
    return result;
  }
  result = startComponent + separator + result;
  if (result.length > maxLen) {
    return "..." + result.substring(result.length - maxLen - 3);
  }
  return result;
}
__name(shortenPath, "shortenPath");
function makeRelative(targetPath, rootDirectory) {
  const resolvedTargetPath = path.resolve(targetPath);
  const resolvedRootDirectory = path.resolve(rootDirectory);
  const relativePath = path.relative(resolvedRootDirectory, resolvedTargetPath);
  return relativePath || ".";
}
__name(makeRelative, "makeRelative");
function escapePath(filePath) {
  let result = "";
  for (let i = 0; i < filePath.length; i++) {
    const char = filePath[i];
    let backslashCount = 0;
    for (let j = i - 1; j >= 0 && filePath[j] === "\\"; j--) {
      backslashCount++;
    }
    const isAlreadyEscaped = backslashCount % 2 === 1;
    if (!isAlreadyEscaped && SHELL_SPECIAL_CHARS.test(char)) {
      result += "\\" + char;
    } else {
      result += char;
    }
  }
  return result;
}
__name(escapePath, "escapePath");
function unescapePath(filePath) {
  return filePath.replace(new RegExp(`\\\\([${SHELL_SPECIAL_CHARS.source.slice(1, -1)}])`, "g"), "$1");
}
__name(unescapePath, "unescapePath");
function getProjectHash(projectRoot) {
  return crypto.createHash("sha256").update(projectRoot).digest("hex");
}
__name(getProjectHash, "getProjectHash");
function isSubpath(parentPath, childPath) {
  const isWindows = os.platform() === "win32";
  const pathModule = isWindows ? path.win32 : path;
  const relative = pathModule.relative(parentPath, childPath);
  return !relative.startsWith(`..${pathModule.sep}`) && relative !== ".." && !pathModule.isAbsolute(relative);
}
__name(isSubpath, "isSubpath");
function resolvePath(baseDir = process.cwd(), relativePath) {
  const homeDir = os.homedir();
  if (relativePath === "~") {
    return homeDir;
  } else if (relativePath.startsWith("~/")) {
    return path.join(homeDir, relativePath.slice(2));
  } else if (path.isAbsolute(relativePath)) {
    return relativePath;
  } else {
    return path.resolve(baseDir, relativePath);
  }
}
__name(resolvePath, "resolvePath");
function validatePath(config, resolvedPath, options = {}) {
  const { allowFiles = false } = options;
  const workspaceContext = config.getWorkspaceContext();
  if (!workspaceContext.isPathWithinWorkspace(resolvedPath)) {
    throw new Error("Path is not within workspace");
  }
  try {
    const stats = fs.statSync(resolvedPath);
    if (!allowFiles && !stats.isDirectory()) {
      throw new Error(`Path is not a directory: ${resolvedPath}`);
    }
  } catch (error) {
    if (isNodeError(error) && error.code === "ENOENT") {
      throw new Error(`Path does not exist: ${resolvedPath}`);
    }
    throw error;
  }
}
__name(validatePath, "validatePath");
function resolveAndValidatePath(config, relativePath, options = {}) {
  const targetDir = config.getTargetDir();
  if (!relativePath) {
    return targetDir;
  }
  const resolvedPath = resolvePath(targetDir, relativePath);
  validatePath(config, resolvedPath, options);
  return resolvedPath;
}
__name(resolveAndValidatePath, "resolveAndValidatePath");

// packages/core/dist/src/papert/papertOAuth2.js
import { randomUUID as randomUUID2 } from "node:crypto";

// packages/core/dist/src/papert/sharedTokenManager.js
init_esbuild_shims();
import path2 from "node:path";
import { promises as fs2, unlinkSync } from "node:fs";
import * as os2 from "os";
import { randomUUID } from "node:crypto";
var TOKEN_REFRESH_BUFFER_MS = 30 * 1e3;
var LOCK_TIMEOUT_MS = 1e4;
var CACHE_CHECK_INTERVAL_MS = 5e3;
var DEFAULT_LOCK_CONFIG = {
  maxAttempts: 20,
  // Reduced from 50 to prevent excessive waiting
  attemptInterval: 100,
  // Reduced from 200ms to check more frequently
  maxInterval: 2e3
  // Maximum interval for exponential backoff
};
var TokenError;
(function(TokenError2) {
  TokenError2["REFRESH_FAILED"] = "REFRESH_FAILED";
  TokenError2["NO_REFRESH_TOKEN"] = "NO_REFRESH_TOKEN";
  TokenError2["LOCK_TIMEOUT"] = "LOCK_TIMEOUT";
  TokenError2["FILE_ACCESS_ERROR"] = "FILE_ACCESS_ERROR";
  TokenError2["NETWORK_ERROR"] = "NETWORK_ERROR";
})(TokenError || (TokenError = {}));
var TokenManagerError = class extends Error {
  static {
    __name(this, "TokenManagerError");
  }
  type;
  originalError;
  constructor(type, message, originalError) {
    super(message);
    this.type = type;
    this.originalError = originalError;
    this.name = "TokenManagerError";
  }
};
function validateCredentials(data) {
  if (!data || typeof data !== "object") {
    throw new Error("Invalid credentials format");
  }
  const creds = data;
  const requiredFields = [
    "access_token",
    "refresh_token",
    "token_type"
  ];
  for (const field of requiredFields) {
    if (!creds[field] || typeof creds[field] !== "string") {
      throw new Error(`Invalid credentials: missing ${field}`);
    }
  }
  if (!creds.expiry_date || typeof creds.expiry_date !== "number") {
    throw new Error("Invalid credentials: missing expiry_date");
  }
  return creds;
}
__name(validateCredentials, "validateCredentials");
var SharedTokenManager = class _SharedTokenManager {
  static {
    __name(this, "SharedTokenManager");
  }
  static instance = null;
  /**
   * In-memory cache for credentials and file state tracking
   */
  memoryCache = {
    credentials: null,
    fileModTime: 0,
    lastCheck: 0
  };
  /**
   * Promise tracking any ongoing token refresh operation
   */
  refreshPromise = null;
  /**
   * Promise tracking any ongoing file check operation to prevent concurrent checks
   */
  checkPromise = null;
  /**
   * Whether cleanup handlers have been registered
   */
  cleanupHandlersRegistered = false;
  /**
   * Reference to cleanup functions for proper removal
   */
  cleanupFunction = null;
  /**
   * Lock configuration for testing purposes
   */
  lockConfig = DEFAULT_LOCK_CONFIG;
  /**
   * Private constructor for singleton pattern
   */
  constructor() {
    this.registerCleanupHandlers();
  }
  /**
   * Get the singleton instance
   * @returns The shared token manager instance
   */
  static getInstance() {
    if (!_SharedTokenManager.instance) {
      _SharedTokenManager.instance = new _SharedTokenManager();
    }
    return _SharedTokenManager.instance;
  }
  /**
   * Set up handlers to clean up lock files when the process exits
   */
  registerCleanupHandlers() {
    if (this.cleanupHandlersRegistered) {
      return;
    }
    this.cleanupFunction = () => {
      try {
        const lockPath = this.getLockFilePath();
        unlinkSync(lockPath);
      } catch (_error) {
      }
    };
    process.on("exit", this.cleanupFunction);
    process.on("SIGINT", this.cleanupFunction);
    process.on("SIGTERM", this.cleanupFunction);
    process.on("uncaughtException", this.cleanupFunction);
    process.on("unhandledRejection", this.cleanupFunction);
    this.cleanupHandlersRegistered = true;
  }
  /**
   * Get valid OAuth credentials, refreshing them if necessary
   *
   * @param papertClient - The OAuth2 client instance
   * @param forceRefresh - If true, refresh token even if current one is still valid
   * @returns Promise resolving to valid credentials
   * @throws TokenManagerError if unable to obtain valid credentials
   */
  async getValidCredentials(papertClient, forceRefresh = false) {
    try {
      await this.checkAndReloadIfNeeded(papertClient);
      if (!forceRefresh && this.memoryCache.credentials && this.isTokenValid(this.memoryCache.credentials)) {
        return this.memoryCache.credentials;
      }
      let currentRefreshPromise = this.refreshPromise;
      if (!currentRefreshPromise) {
        currentRefreshPromise = this.performTokenRefresh(papertClient, forceRefresh);
        this.refreshPromise = currentRefreshPromise;
      }
      try {
        const result = await currentRefreshPromise;
        return result;
      } finally {
        if (this.refreshPromise === currentRefreshPromise) {
          this.refreshPromise = null;
        }
      }
    } catch (error) {
      if (error instanceof TokenManagerError) {
        throw error;
      }
      throw new TokenManagerError(TokenError.REFRESH_FAILED, `Failed to get valid credentials: ${error instanceof Error ? error.message : String(error)}`, error);
    }
  }
  /**
   * Check if the credentials file was updated by another process and reload if so
   * Uses promise-based locking to prevent concurrent file checks
   */
  async checkAndReloadIfNeeded(papertClient) {
    if (this.checkPromise) {
      await this.checkPromise;
      return;
    }
    if (this.refreshPromise) {
      return;
    }
    const now = Date.now();
    if (now - this.memoryCache.lastCheck < CACHE_CHECK_INTERVAL_MS) {
      return;
    }
    this.checkPromise = this.performFileCheck(papertClient, now);
    try {
      await this.checkPromise;
    } finally {
      this.checkPromise = null;
    }
  }
  /**
   * Utility method to add timeout to any promise operation
   * Properly cleans up the timeout when the promise completes
   */
  withTimeout(promise, timeoutMs, operationType = "Operation") {
    let timeoutId;
    return Promise.race([
      promise.finally(() => {
        if (timeoutId) {
          clearTimeout(timeoutId);
        }
      }),
      new Promise((_, reject) => {
        timeoutId = setTimeout(() => reject(new Error(`${operationType} timed out after ${timeoutMs}ms`)), timeoutMs);
      })
    ]);
  }
  /**
   * Perform the actual file check and reload operation
   * This is separated to enable proper promise-based synchronization
   */
  async performFileCheck(papertClient, checkTime) {
    this.memoryCache.lastCheck = checkTime;
    try {
      const filePath = this.getCredentialFilePath();
      const stats = await this.withTimeout(fs2.stat(filePath), 3e3, "File operation");
      const fileModTime = stats.mtimeMs;
      if (fileModTime > this.memoryCache.fileModTime) {
        await this.reloadCredentialsFromFile(papertClient);
        this.memoryCache.fileModTime = fileModTime;
      }
    } catch (error) {
      if (error instanceof Error && "code" in error && error.code !== "ENOENT") {
        this.updateCacheState(null, 0, checkTime);
        throw new TokenManagerError(TokenError.FILE_ACCESS_ERROR, `Failed to access credentials file: ${error.message}`, error);
      }
      this.memoryCache.fileModTime = 0;
    }
  }
  /**
   * Force a file check without time-based throttling (used during refresh operations)
   */
  async forceFileCheck(papertClient) {
    try {
      const filePath = this.getCredentialFilePath();
      const stats = await fs2.stat(filePath);
      const fileModTime = stats.mtimeMs;
      if (fileModTime > this.memoryCache.fileModTime) {
        await this.reloadCredentialsFromFile(papertClient);
        this.memoryCache.fileModTime = fileModTime;
        this.memoryCache.lastCheck = Date.now();
      }
    } catch (error) {
      if (error instanceof Error && "code" in error && error.code !== "ENOENT") {
        this.updateCacheState(null, 0);
        throw new TokenManagerError(TokenError.FILE_ACCESS_ERROR, `Failed to access credentials file during refresh: ${error.message}`, error);
      }
      this.memoryCache.fileModTime = 0;
    }
  }
  /**
   * Load credentials from the file system into memory cache and sync with papertClient
   */
  async reloadCredentialsFromFile(papertClient) {
    try {
      const filePath = this.getCredentialFilePath();
      const content = await fs2.readFile(filePath, "utf-8");
      const parsedData = JSON.parse(content);
      const credentials = validateCredentials(parsedData);
      const previousCredentials = this.memoryCache.credentials;
      this.memoryCache.credentials = credentials;
      try {
        if (papertClient) {
          papertClient.setCredentials(credentials);
        }
      } catch (clientError) {
        this.memoryCache.credentials = previousCredentials;
        throw clientError;
      }
    } catch (error) {
      if (error instanceof Error && error.message.includes("Invalid credentials")) {
        console.warn(`Failed to validate credentials file: ${error.message}`);
      }
      this.memoryCache.credentials = null;
    }
  }
  /**
   * Refresh the OAuth token using file locking to prevent concurrent refreshes
   *
   * @param papertClient - The OAuth2 client instance
   * @param forceRefresh - If true, skip checking if token is already valid after getting lock
   * @returns Promise resolving to refreshed credentials
   * @throws TokenManagerError if refresh fails or lock cannot be acquired
   */
  async performTokenRefresh(papertClient, forceRefresh = false) {
    const startTime = Date.now();
    const lockPath = this.getLockFilePath();
    try {
      const currentCredentials = papertClient.getCredentials();
      if (!currentCredentials.refresh_token) {
        throw new TokenManagerError(TokenError.NO_REFRESH_TOKEN, "No refresh token available for token refresh");
      }
      await this.acquireLock(lockPath);
      const lockAcquisitionTime = Date.now() - startTime;
      if (lockAcquisitionTime > 5e3) {
        console.warn(`Token refresh lock acquisition took ${lockAcquisitionTime}ms`);
      }
      await this.forceFileCheck(papertClient);
      if (!forceRefresh && this.memoryCache.credentials && this.isTokenValid(this.memoryCache.credentials)) {
        return this.memoryCache.credentials;
      }
      const response = await papertClient.refreshAccessToken();
      const totalOperationTime = Date.now() - startTime;
      if (totalOperationTime > 1e4) {
        console.warn(`Token refresh operation took ${totalOperationTime}ms`);
      }
      if (!response || isErrorResponse(response)) {
        const errorData = response;
        throw new TokenManagerError(TokenError.REFRESH_FAILED, `Token refresh failed: ${errorData?.error || "Unknown error"} - ${errorData?.error_description || "No details provided"}`);
      }
      const tokenData = response;
      if (!tokenData.access_token) {
        throw new TokenManagerError(TokenError.REFRESH_FAILED, "Failed to refresh access token: no token returned");
      }
      const credentials = {
        access_token: tokenData.access_token,
        token_type: tokenData.token_type,
        refresh_token: tokenData.refresh_token || currentCredentials.refresh_token,
        resource_url: tokenData.resource_url,
        expiry_date: Date.now() + tokenData.expires_in * 1e3
      };
      this.memoryCache.credentials = credentials;
      papertClient.setCredentials(credentials);
      await this.saveCredentialsToFile(credentials);
      return credentials;
    } catch (error) {
      if (error instanceof CredentialsClearRequiredError) {
        console.debug("SharedTokenManager: Clearing memory cache due to credentials clear requirement");
        this.memoryCache.credentials = null;
        this.memoryCache.fileModTime = 0;
        this.refreshPromise = null;
        throw new TokenManagerError(TokenError.REFRESH_FAILED, error.message, error);
      }
      if (error instanceof TokenManagerError) {
        throw error;
      }
      if (error instanceof Error && (error.message.includes("fetch") || error.message.includes("network") || error.message.includes("timeout"))) {
        throw new TokenManagerError(TokenError.NETWORK_ERROR, `Network error during token refresh: ${error.message}`, error);
      }
      throw new TokenManagerError(TokenError.REFRESH_FAILED, `Unexpected error during token refresh: ${error instanceof Error ? error.message : String(error)}`, error);
    } finally {
      await this.releaseLock(lockPath);
    }
  }
  /**
   * Save credentials to file and update the cached file modification time
   *
   * @param credentials - The credentials to save
   */
  async saveCredentialsToFile(credentials) {
    const filePath = this.getCredentialFilePath();
    const dirPath = path2.dirname(filePath);
    const tempPath = `${filePath}.tmp.${randomUUID()}`;
    try {
      await this.withTimeout(fs2.mkdir(dirPath, { recursive: true, mode: 448 }), 5e3, "File operation");
    } catch (error) {
      throw new TokenManagerError(TokenError.FILE_ACCESS_ERROR, `Failed to create credentials directory: ${error instanceof Error ? error.message : String(error)}`, error);
    }
    const credString = JSON.stringify(credentials, null, 2);
    try {
      await this.withTimeout(fs2.writeFile(tempPath, credString, { mode: 384 }), 5e3, "File operation");
      await this.withTimeout(fs2.rename(tempPath, filePath), 5e3, "File operation");
      const stats = await this.withTimeout(fs2.stat(filePath), 5e3, "File operation");
      this.memoryCache.fileModTime = stats.mtimeMs;
    } catch (error) {
      try {
        await this.withTimeout(fs2.unlink(tempPath), 1e3, "File operation");
      } catch (_cleanupError) {
      }
      throw new TokenManagerError(TokenError.FILE_ACCESS_ERROR, `Failed to write credentials file: ${error instanceof Error ? error.message : String(error)}`, error);
    }
  }
  /**
   * Check if the token is valid and not expired
   *
   * @param credentials - The credentials to validate
   * @returns true if token is valid and not expired, false otherwise
   */
  isTokenValid(credentials) {
    if (!credentials.expiry_date || !credentials.access_token) {
      return false;
    }
    return Date.now() < credentials.expiry_date - TOKEN_REFRESH_BUFFER_MS;
  }
  /**
   * Get the full path to the credentials file
   *
   * @returns The absolute path to the credentials file
   */
  getCredentialFilePath() {
    return path2.join(os2.homedir(), PAPERT_DIR, PAPERT_CREDENTIAL_FILENAME);
  }
  /**
   * Get the full path to the lock file
   *
   * @returns The absolute path to the lock file
   */
  getLockFilePath() {
    return path2.join(os2.homedir(), PAPERT_DIR, PAPERT_LOCK_FILENAME);
  }
  /**
   * Acquire a file lock to prevent other processes from refreshing tokens simultaneously
   *
   * @param lockPath - Path to the lock file
   * @throws TokenManagerError if lock cannot be acquired within timeout period
   */
  async acquireLock(lockPath) {
    const { maxAttempts, attemptInterval, maxInterval } = this.lockConfig;
    const lockId = randomUUID();
    let currentInterval = attemptInterval;
    for (let attempt = 0; attempt < maxAttempts; attempt++) {
      try {
        await fs2.writeFile(lockPath, lockId, { flag: "wx" });
        return;
      } catch (error) {
        if (error.code === "EEXIST") {
          try {
            const stats = await fs2.stat(lockPath);
            const lockAge = Date.now() - stats.mtimeMs;
            if (lockAge > LOCK_TIMEOUT_MS) {
              const tempPath = `${lockPath}.stale.${randomUUID()}`;
              try {
                await fs2.rename(lockPath, tempPath);
                await fs2.unlink(tempPath);
                console.warn(`Removed stale lock file: ${lockPath} (age: ${lockAge}ms)`);
                continue;
              } catch (renameError) {
                console.warn(`Failed to remove stale lock file ${lockPath}: ${renameError instanceof Error ? renameError.message : String(renameError)}`);
              }
            }
          } catch (statError) {
            console.warn(`Failed to stat lock file ${lockPath}: ${statError instanceof Error ? statError.message : String(statError)}`);
          }
          await new Promise((resolve) => setTimeout(resolve, currentInterval));
          currentInterval = Math.min(currentInterval * 1.5, maxInterval);
        } else {
          throw new TokenManagerError(TokenError.FILE_ACCESS_ERROR, `Failed to create lock file: ${error instanceof Error ? error.message : String(error)}`, error);
        }
      }
    }
    throw new TokenManagerError(TokenError.LOCK_TIMEOUT, "Failed to acquire file lock for token refresh: timeout exceeded");
  }
  /**
   * Release the file lock
   *
   * @param lockPath - Path to the lock file
   */
  async releaseLock(lockPath) {
    try {
      await fs2.unlink(lockPath);
    } catch (error) {
      if (error.code !== "ENOENT") {
        console.warn(`Failed to release lock file ${lockPath}: ${error instanceof Error ? error.message : String(error)}`);
      }
    }
  }
  /**
   * Atomically update cache state to prevent inconsistent intermediate states
   * @param credentials - New credentials to cache
   * @param fileModTime - File modification time
   * @param lastCheck - Last check timestamp (optional, defaults to current time)
   */
  updateCacheState(credentials, fileModTime, lastCheck) {
    this.memoryCache = {
      credentials,
      fileModTime,
      lastCheck: lastCheck ?? Date.now()
    };
  }
  /**
   * Clear all cached data and reset the manager to initial state
   */
  clearCache() {
    this.updateCacheState(null, 0, 0);
    this.refreshPromise = null;
    this.checkPromise = null;
  }
  /**
   * Get the current cached credentials (may be expired)
   *
   * @returns The currently cached credentials or null
   */
  getCurrentCredentials() {
    return this.memoryCache.credentials;
  }
  /**
   * Check if there's an ongoing refresh operation
   *
   * @returns true if refresh is in progress, false otherwise
   */
  isRefreshInProgress() {
    return this.refreshPromise !== null;
  }
  /**
   * Set lock configuration for testing purposes
   * @param config - Lock configuration
   */
  setLockConfig(config) {
    this.lockConfig = { ...DEFAULT_LOCK_CONFIG, ...config };
  }
  /**
   * Clean up event listeners (primarily for testing)
   */
  cleanup() {
    if (this.cleanupFunction && this.cleanupHandlersRegistered) {
      this.cleanupFunction();
      process.removeListener("exit", this.cleanupFunction);
      process.removeListener("SIGINT", this.cleanupFunction);
      process.removeListener("SIGTERM", this.cleanupFunction);
      process.removeListener("uncaughtException", this.cleanupFunction);
      process.removeListener("unhandledRejection", this.cleanupFunction);
      this.cleanupHandlersRegistered = false;
      this.cleanupFunction = null;
    }
  }
  /**
   * Get a summary of the current state for debugging
   *
   * @returns Object containing current state information
   */
  getDebugInfo() {
    const hasCredentials = !!this.memoryCache.credentials;
    const credentialsExpired = hasCredentials ? !this.isTokenValid(this.memoryCache.credentials) : false;
    return {
      hasCredentials,
      credentialsExpired,
      isRefreshing: this.isRefreshInProgress(),
      cacheAge: Date.now() - this.memoryCache.lastCheck
    };
  }
};

// packages/core/dist/src/papert/papertOAuth2.js
var PAPERT_OAUTH_BASE_URL = "https://chat.papert.ai";
var PAPERT_OAUTH_DEVICE_CODE_ENDPOINT = `${PAPERT_OAUTH_BASE_URL}/api/v1/oauth2/device/code`;
var PAPERT_OAUTH_TOKEN_ENDPOINT = `${PAPERT_OAUTH_BASE_URL}/api/v1/oauth2/token`;
var PAPERT_OAUTH_CLIENT_ID = "f0304373b74a44d2b584a3fb70ca9e56";
var PAPERT_OAUTH_SCOPE = "openid profile email model.completion";
var PAPERT_OAUTH_GRANT_TYPE = "urn:ietf:params:oauth:grant-type:device_code";
function generateCodeVerifier() {
  return crypto2.randomBytes(32).toString("base64url");
}
__name(generateCodeVerifier, "generateCodeVerifier");
function generateCodeChallenge(codeVerifier) {
  const hash = crypto2.createHash("sha256");
  hash.update(codeVerifier);
  return hash.digest("base64url");
}
__name(generateCodeChallenge, "generateCodeChallenge");
function generatePKCEPair() {
  const codeVerifier = generateCodeVerifier();
  const codeChallenge = generateCodeChallenge(codeVerifier);
  return { code_verifier: codeVerifier, code_challenge: codeChallenge };
}
__name(generatePKCEPair, "generatePKCEPair");
function objectToUrlEncoded(data) {
  return Object.keys(data).map((key) => `${encodeURIComponent(key)}=${encodeURIComponent(data[key])}`).join("&");
}
__name(objectToUrlEncoded, "objectToUrlEncoded");
var CredentialsClearRequiredError = class extends Error {
  static {
    __name(this, "CredentialsClearRequiredError");
  }
  originalError;
  constructor(message, originalError) {
    super(message);
    this.originalError = originalError;
    this.name = "CredentialsClearRequiredError";
  }
};
function isDeviceAuthorizationSuccess(response) {
  return "device_code" in response;
}
__name(isDeviceAuthorizationSuccess, "isDeviceAuthorizationSuccess");
function isDeviceTokenSuccess(response) {
  return "access_token" in response && response.access_token !== null && response.access_token !== void 0 && typeof response.access_token === "string" && response.access_token.length > 0;
}
__name(isDeviceTokenSuccess, "isDeviceTokenSuccess");
function isDeviceTokenPending(response) {
  return "status" in response && response.status === "pending";
}
__name(isDeviceTokenPending, "isDeviceTokenPending");
function isErrorResponse(response) {
  return "error" in response;
}
__name(isErrorResponse, "isErrorResponse");
var PapertOAuth2Client = class {
  static {
    __name(this, "PapertOAuth2Client");
  }
  credentials = {};
  sharedManager;
  constructor() {
    this.sharedManager = SharedTokenManager.getInstance();
  }
  setCredentials(credentials) {
    this.credentials = credentials;
  }
  getCredentials() {
    return this.credentials;
  }
  async getAccessToken() {
    try {
      const credentials = await this.sharedManager.getValidCredentials(this);
      return { token: credentials.access_token };
    } catch (error) {
      console.warn("Failed to get access token from shared manager:", error);
      return { token: void 0 };
    }
  }
  async requestDeviceAuthorization(options) {
    const bodyData = {
      client_id: PAPERT_OAUTH_CLIENT_ID,
      scope: options.scope,
      code_challenge: options.code_challenge,
      code_challenge_method: options.code_challenge_method
    };
    const response = await fetch(PAPERT_OAUTH_DEVICE_CODE_ENDPOINT, {
      method: "POST",
      headers: {
        "Content-Type": "application/x-www-form-urlencoded",
        Accept: "application/json",
        "x-request-id": randomUUID2()
      },
      body: objectToUrlEncoded(bodyData)
    });
    if (!response.ok) {
      const errorData = await response.text();
      throw new Error(`Device authorization failed: ${response.status} ${response.statusText}. Response: ${errorData}`);
    }
    const result = await response.json();
    console.debug("Device authorization result:", result);
    if (!isDeviceAuthorizationSuccess(result)) {
      const errorData = result;
      throw new Error(`Device authorization failed: ${errorData?.error || "Unknown error"} - ${errorData?.error_description || "No details provided"}`);
    }
    return result;
  }
  async pollDeviceToken(options) {
    const bodyData = {
      grant_type: PAPERT_OAUTH_GRANT_TYPE,
      client_id: PAPERT_OAUTH_CLIENT_ID,
      device_code: options.device_code,
      code_verifier: options.code_verifier
    };
    const response = await fetch(PAPERT_OAUTH_TOKEN_ENDPOINT, {
      method: "POST",
      headers: {
        "Content-Type": "application/x-www-form-urlencoded",
        Accept: "application/json"
      },
      body: objectToUrlEncoded(bodyData)
    });
    if (!response.ok) {
      const responseText = await response.text();
      let errorData = null;
      try {
        errorData = JSON.parse(responseText);
      } catch (_parseError) {
        const error2 = new Error(`Device token poll failed: ${response.status} ${response.statusText}. Response: ${responseText}`);
        error2.status = response.status;
        throw error2;
      }
      if (response.status === 400 && errorData.error === "authorization_pending") {
        return { status: "pending" };
      }
      if (response.status === 429 && errorData.error === "slow_down") {
        return {
          status: "pending",
          slowDown: true
        };
      }
      const error = new Error(`Device token poll failed: ${errorData.error || "Unknown error"} - ${errorData.error_description}`);
      error.status = response.status;
      throw error;
    }
    return await response.json();
  }
  async refreshAccessToken() {
    if (!this.credentials.refresh_token) {
      throw new Error("No refresh token available");
    }
    const bodyData = {
      grant_type: "refresh_token",
      refresh_token: this.credentials.refresh_token,
      client_id: PAPERT_OAUTH_CLIENT_ID
    };
    const response = await fetch(PAPERT_OAUTH_TOKEN_ENDPOINT, {
      method: "POST",
      headers: {
        "Content-Type": "application/x-www-form-urlencoded",
        Accept: "application/json"
      },
      body: objectToUrlEncoded(bodyData)
    });
    if (!response.ok) {
      const errorData = await response.text();
      if (response.status === 400) {
        await clearPapertCredentials();
        throw new CredentialsClearRequiredError("Refresh token expired or invalid. Please use '/auth' to re-authenticate.", { status: response.status, response: errorData });
      }
      throw new Error(`Token refresh failed: ${response.status} ${response.statusText}. Response: ${errorData}`);
    }
    const responseData = await response.json();
    if (isErrorResponse(responseData)) {
      const errorData = responseData;
      throw new Error(`Token refresh failed: ${errorData?.error || "Unknown error"} - ${errorData?.error_description || "No details provided"}`);
    }
    const tokenData = responseData;
    const tokens = {
      access_token: tokenData.access_token,
      token_type: tokenData.token_type,
      // Use new refresh token if provided, otherwise preserve existing one
      refresh_token: tokenData.refresh_token || this.credentials.refresh_token,
      resource_url: tokenData.resource_url,
      // Include resource_url if provided
      expiry_date: Date.now() + tokenData.expires_in * 1e3
    };
    this.setCredentials(tokens);
    return responseData;
  }
};
var PapertOAuth2Event;
(function(PapertOAuth2Event2) {
  PapertOAuth2Event2["AuthUri"] = "auth-uri";
  PapertOAuth2Event2["AuthProgress"] = "auth-progress";
  PapertOAuth2Event2["AuthCancel"] = "auth-cancel";
})(PapertOAuth2Event || (PapertOAuth2Event = {}));
var papertOAuth2Events = new EventEmitter();
async function getPapertOAuthClient(config, options) {
  const client = new PapertOAuth2Client();
  const sharedManager = SharedTokenManager.getInstance();
  try {
    const credentials = await sharedManager.getValidCredentials(client);
    client.setCredentials(credentials);
    return client;
  } catch (error) {
    if (error instanceof TokenManagerError) {
      switch (error.type) {
        case TokenError.NO_REFRESH_TOKEN:
          console.debug("No refresh token available, proceeding with device flow");
          break;
        case TokenError.REFRESH_FAILED:
          console.debug("Token refresh failed, proceeding with device flow");
          break;
        case TokenError.NETWORK_ERROR:
          console.warn("Network error during token refresh, trying device flow");
          break;
        default:
          console.warn("Token manager error:", error.message);
      }
    }
    if (await loadCachedPapertCredentials(client)) {
      const result2 = await authWithPapertDeviceFlow(client, config);
      if (!result2.success) {
        const errorMessage = result2.message || "Papert OAuth authentication failed";
        throw new Error(errorMessage);
      }
      return client;
    }
    if (options?.requireCachedCredentials) {
      throw new Error("No cached Papert-OAuth credentials found. Please re-authenticate.");
    }
    const result = await authWithPapertDeviceFlow(client, config);
    if (!result.success) {
      if (result.reason === "timeout") {
        papertOAuth2Events.emit(PapertOAuth2Event.AuthProgress, "timeout", "Authentication timed out. Please try again or select a different authentication method.");
      }
      const errorMessage = result.message || (() => {
        switch (result.reason) {
          case "timeout":
            return "Papert OAuth authentication timed out";
          case "cancelled":
            return "Papert OAuth authentication was cancelled by user";
          case "rate_limit":
            return "Too many request for Papert OAuth authentication, please try again later.";
          case "error":
          default:
            return "Papert OAuth authentication failed";
        }
      })();
      throw new Error(errorMessage);
    }
    return client;
  }
}
__name(getPapertOAuthClient, "getPapertOAuthClient");
async function authWithPapertDeviceFlow(client, config) {
  let isCancelled = false;
  const cancelHandler = /* @__PURE__ */ __name(() => {
    isCancelled = true;
  }, "cancelHandler");
  papertOAuth2Events.once(PapertOAuth2Event.AuthCancel, cancelHandler);
  try {
    const { code_verifier, code_challenge } = generatePKCEPair();
    const deviceAuth = await client.requestDeviceAuthorization({
      scope: PAPERT_OAUTH_SCOPE,
      code_challenge,
      code_challenge_method: "S256"
    });
    if (!isDeviceAuthorizationSuccess(deviceAuth)) {
      const errorData = deviceAuth;
      throw new Error(`Device authorization failed: ${errorData?.error || "Unknown error"} - ${errorData?.error_description || "No details provided"}`);
    }
    papertOAuth2Events.emit(PapertOAuth2Event.AuthUri, deviceAuth);
    const showFallbackMessage = /* @__PURE__ */ __name(() => {
      console.log("\n=== Papert OAuth Device Authorization ===");
      console.log("Please visit the following URL in your browser to authorize:");
      console.log(`
${deviceAuth.verification_uri_complete}
`);
      console.log("Waiting for authorization to complete...\n");
    }, "showFallbackMessage");
    if (!config.isBrowserLaunchSuppressed()) {
      try {
        const childProcess = await open_default(deviceAuth.verification_uri_complete);
        if (childProcess) {
          childProcess.on("error", () => {
            console.debug("Failed to open browser. Visit this URL to authorize:");
            showFallbackMessage();
          });
        }
      } catch (_err) {
        showFallbackMessage();
      }
    } else {
      showFallbackMessage();
    }
    papertOAuth2Events.emit(PapertOAuth2Event.AuthProgress, "polling", "Waiting for authorization...");
    console.debug("Waiting for authorization...\n");
    let pollInterval = 2e3;
    const maxAttempts = Math.ceil(deviceAuth.expires_in / (pollInterval / 1e3));
    for (let attempt = 0; attempt < maxAttempts; attempt++) {
      if (isCancelled) {
        const message = "Authentication cancelled by user.";
        console.debug("\n" + message);
        papertOAuth2Events.emit(PapertOAuth2Event.AuthProgress, "error", message);
        return { success: false, reason: "cancelled", message };
      }
      try {
        console.debug("polling for token...");
        const tokenResponse = await client.pollDeviceToken({
          device_code: deviceAuth.device_code,
          code_verifier
        });
        if (isDeviceTokenSuccess(tokenResponse)) {
          const tokenData = tokenResponse;
          const credentials = {
            access_token: tokenData.access_token,
            // Safe to assert as non-null due to isDeviceTokenSuccess check
            refresh_token: tokenData.refresh_token || void 0,
            token_type: tokenData.token_type,
            resource_url: tokenData.resource_url,
            expiry_date: tokenData.expires_in ? Date.now() + tokenData.expires_in * 1e3 : void 0
          };
          client.setCredentials(credentials);
          await cachePapertCredentials(credentials);
          papertOAuth2Events.emit(PapertOAuth2Event.AuthProgress, "success", "Authentication successful! Access token obtained.");
          console.debug("Authentication successful! Access token obtained.");
          return { success: true };
        }
        if (isDeviceTokenPending(tokenResponse)) {
          const pendingData = tokenResponse;
          if (pendingData.slowDown) {
            pollInterval = Math.min(pollInterval * 1.5, 1e4);
            console.debug(`
Server requested to slow down, increasing poll interval to ${pollInterval}ms'`);
          } else {
            pollInterval = 2e3;
          }
          papertOAuth2Events.emit(PapertOAuth2Event.AuthProgress, "polling", `Polling... (attempt ${attempt + 1}/${maxAttempts})`);
          await new Promise((resolve) => {
            const checkInterval = 100;
            let elapsedTime = 0;
            const intervalId = setInterval(() => {
              elapsedTime += checkInterval;
              if (isCancelled) {
                clearInterval(intervalId);
                resolve();
                return;
              }
              if (elapsedTime >= pollInterval) {
                clearInterval(intervalId);
                resolve();
                return;
              }
            }, checkInterval);
          });
          if (isCancelled) {
            const message = "Authentication cancelled by user.";
            console.debug("\n" + message);
            papertOAuth2Events.emit(PapertOAuth2Event.AuthProgress, "error", message);
            return { success: false, reason: "cancelled", message };
          }
          continue;
        }
        if (isErrorResponse(tokenResponse)) {
          const errorData = tokenResponse;
          throw new Error(`Token polling failed: ${errorData?.error || "Unknown error"} - ${errorData?.error_description || "No details provided"}`);
        }
      } catch (error) {
        const errorMessage = error instanceof Error ? error.message : String(error);
        const statusCode = error instanceof Error ? error.status : null;
        const handleError = /* @__PURE__ */ __name((reason, message2, eventType = "error") => {
          papertOAuth2Events.emit(PapertOAuth2Event.AuthProgress, eventType, message2);
          console.error("\n" + message2);
          return { success: false, reason, message: message2 };
        }, "handleError");
        if (errorMessage.includes("Failed to cache credentials")) {
          return handleError("error", errorMessage);
        }
        if (errorMessage.includes("401") || statusCode === 401) {
          return handleError("error", "Device code expired or invalid, please restart the authorization process.");
        }
        if (errorMessage.includes("429") || statusCode === 429) {
          return handleError("rate_limit", "Too many requests. The server is rate limiting our requests. Please select a different authentication method or try again later.", "rate_limit");
        }
        const message = `Error polling for token: ${errorMessage}`;
        papertOAuth2Events.emit(PapertOAuth2Event.AuthProgress, "error", message);
        if (isCancelled) {
          const message2 = "Authentication cancelled by user.";
          return { success: false, reason: "cancelled", message: message2 };
        }
        await new Promise((resolve) => setTimeout(resolve, pollInterval));
      }
    }
    const timeoutMessage = "Authorization timeout, please restart the process.";
    papertOAuth2Events.emit(PapertOAuth2Event.AuthProgress, "timeout", timeoutMessage);
    console.error("\n" + timeoutMessage);
    return { success: false, reason: "timeout", message: timeoutMessage };
  } catch (error) {
    const errorMessage = error instanceof Error ? error.message : String(error);
    const message = `Device authorization flow failed: ${errorMessage}`;
    console.error(message);
    return { success: false, reason: "error", message };
  } finally {
    papertOAuth2Events.off(PapertOAuth2Event.AuthCancel, cancelHandler);
  }
}
__name(authWithPapertDeviceFlow, "authWithPapertDeviceFlow");
async function loadCachedPapertCredentials(client) {
  try {
    const keyFile = getPapertCachedCredentialPath();
    const creds = await fs3.readFile(keyFile, "utf-8");
    const credentials = JSON.parse(creds);
    client.setCredentials(credentials);
    const { token } = await client.getAccessToken();
    if (!token) {
      return false;
    }
    return true;
  } catch (_) {
    return false;
  }
}
__name(loadCachedPapertCredentials, "loadCachedPapertCredentials");
async function cachePapertCredentials(credentials) {
  const filePath = getPapertCachedCredentialPath();
  try {
    await fs3.mkdir(path3.dirname(filePath), { recursive: true });
    const credString = JSON.stringify(credentials, null, 2);
    await fs3.writeFile(filePath, credString);
  } catch (error) {
    const errorMessage = error instanceof Error ? error.message : String(error);
    const errorCode = error instanceof Error && "code" in error ? error.code : void 0;
    if (errorCode === "EACCES") {
      throw new Error(`Failed to cache credentials: Permission denied (EACCES). Current user has no permission to access \`${filePath}\`. Please check permissions.`);
    }
    throw new Error(`Failed to cache credentials: error when creating folder \`${path3.dirname(filePath)}\` and writing to \`${filePath}\`. ${errorMessage}. Please check permissions.`);
  }
}
__name(cachePapertCredentials, "cachePapertCredentials");
async function clearPapertCredentials() {
  try {
    const filePath = getPapertCachedCredentialPath();
    await fs3.unlink(filePath);
    console.debug("Cached Papert credentials cleared successfully.");
  } catch (error) {
    if (error instanceof Error && "code" in error && error.code === "ENOENT") {
      return;
    }
    console.warn("Warning: Failed to clear cached Papert credentials:", error);
  }
}
__name(clearPapertCredentials, "clearPapertCredentials");
function getPapertCachedCredentialPath() {
  return path3.join(os3.homedir(), PAPERT_DIR, PAPERT_CREDENTIAL_FILENAME);
}
__name(getPapertCachedCredentialPath, "getPapertCachedCredentialPath");

export {
  PAPERT_DIR,
  tildeifyPath,
  shortenPath,
  makeRelative,
  escapePath,
  unescapePath,
  getProjectHash,
  isSubpath,
  resolveAndValidatePath,
  generateCodeVerifier,
  generateCodeChallenge,
  generatePKCEPair,
  CredentialsClearRequiredError,
  isDeviceAuthorizationSuccess,
  isDeviceTokenSuccess,
  isDeviceTokenPending,
  isErrorResponse,
  PapertOAuth2Client,
  PapertOAuth2Event,
  papertOAuth2Events,
  getPapertOAuthClient,
  clearPapertCredentials,
  TokenError,
  TokenManagerError,
  SharedTokenManager
};
/**
 * @license
 * * Copyright 2026 Papert-code
 * SPDX-License-Identifier: Apache-2.0
 */
/**
 * @license
 * Copyright 2025 Papert
 * SPDX-License-Identifier: Apache-2.0
 */
