@iaforged/context-code 2.3.0 → 2.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/context-bootstrap.js +8 -1
  2. package/contextcode-bootstrap.js +7 -1
  3. package/dist/src/QueryEngine.js +1 -1
  4. package/dist/src/cli/handlers/auth.js +1 -1
  5. package/dist/src/cli/handlers/modelList.js +1 -1
  6. package/dist/src/cli/structuredIO.js +1 -1
  7. package/dist/src/commands/branch/index.js +1 -1
  8. package/dist/src/commands/login/login.js +1 -1
  9. package/dist/src/commands/profile/index.js +1 -1
  10. package/dist/src/commands/profile/profile.js +1 -1
  11. package/dist/src/commands/provider/index.js +1 -1
  12. package/dist/src/commands/provider/provider.js +1 -1
  13. package/dist/src/components/ConsoleOAuthFlow.js +1 -1
  14. package/dist/src/components/LogoV2/Opus1mMergeNotice.js +1 -1
  15. package/dist/src/components/ModelPicker.js +1 -1
  16. package/dist/src/components/SessionTokenFooter.js +1 -0
  17. package/dist/src/constants/oauth.js +1 -1
  18. package/dist/src/core/providers/providerCore.js +1 -1
  19. package/dist/src/hooks/useTypeahead.js +1 -1
  20. package/dist/src/main.js +1 -1
  21. package/dist/src/screens/REPL.js +1 -1
  22. package/dist/src/services/api/openai.js +1 -1
  23. package/dist/src/services/oauth/auth-code-listener.js +1 -1
  24. package/dist/src/services/oauth/client.js +1 -1
  25. package/dist/src/services/oauth/geminiCli.js +1 -1
  26. package/dist/src/utils/auth.js +1 -1
  27. package/dist/src/utils/claudeInChrome/setup.js +1 -1
  28. package/dist/src/utils/config.js +1 -1
  29. package/dist/src/utils/env.js +1 -1
  30. package/dist/src/utils/envUtils.js +1 -1
  31. package/dist/src/utils/git.js +1 -1
  32. package/dist/src/utils/localInstaller.js +1 -1
  33. package/dist/src/utils/model/configs.js +1 -1
  34. package/dist/src/utils/model/model.js +1 -1
  35. package/dist/src/utils/model/modelAllowlist.js +1 -1
  36. package/dist/src/utils/model/modelOptions.js +1 -1
  37. package/dist/src/utils/model/providerBaseUrls.js +1 -1
  38. package/dist/src/utils/model/providerCatalog.js +1 -1
  39. package/dist/src/utils/model/providerModels.js +1 -1
  40. package/dist/src/utils/model/providerProfiles.js +1 -1
  41. package/dist/src/utils/model/providerProfilesDb.js +1 -1
  42. package/dist/src/utils/model/providers.js +1 -1
  43. package/dist/src/utils/model/validateModel.js +1 -1
  44. package/dist/src/utils/permissions/filesystem.js +1 -1
  45. package/dist/src/utils/ripgrep.js +1 -1
  46. package/dist/webapp/ngsw.json +1 -1
  47. package/package.json +1 -1
@@ -1 +1 @@
1
- import{APIUserAbortError as e}from"@anthropic-ai/sdk/error.js";import{randomUUID as t}from"node:crypto";import{checkAndRefreshOpenAIOAuthTokenIfNeeded as o,getGeminiGoogleAuthHeaders as n,getOpenAICompatibleAccessToken as r,getOpenAIAccessToken as s,handleOpenAIOAuth401Error as i}from"../../utils/auth.js";import{getAPIProvider as a}from"../../utils/model/providers.js";import{getConfiguredProviderBaseUrl as u}from"../../utils/model/providerBaseUrls.js";import{errorMessage as l}from"../../utils/errors.js";import{logForDebugging as p}from"../../utils/debug.js";import{logError as c}from"../../utils/log.js";import{createAssistantAPIErrorMessage as m,createAssistantMessage as d,createUserMessage as f}from"../../utils/messages.js";import{toolToAPISchema as g}from"../../utils/api.js";import{jsonStringify as y}from"../../utils/slowOperations.js";function getOpenAIMaxTimeoutRetries(){const e=process.env.CONTEXT_CODE_MAX_RETRIES;if(!e)return 10;const t=Number.parseInt(e,10);return!Number.isFinite(t)||t<0?10:t}function isRecord(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}function isPlainObject(e){if(!isRecord(e))return!1;const t=Object.getPrototypeOf(e);return t===Object.prototype||null===t}function isJwtToken(e){return 3===e.split(".").length}function getOpenAICompatibleProvider(){const e=a();return"openrouter"===e||"ollama"===e||"ollama-cloud"===e||"gemini-api"===e||"gemini-google"===e||"zai"===e||"nvidia"===e||"custom-openai"===e?e:"openai"}function getOpenAICompatibleProviderLabel(e=getOpenAICompatibleProvider()){switch(e){case"openrouter":return"OpenRouter";case"ollama":return"Ollama";case"ollama-cloud":return"Ollama Cloud";case"gemini-api":return"Gemini API";case"gemini-google":return"Gemini Google";case"zai":return"Z.AI";case"nvidia":return"NVIDIA NIM";case"custom-openai":return"Custom OpenAI";default:return"OpenAI"}}function getOpenAIBaseUrl(e=getOpenAICompatibleProvider()){if("openrouter"===e){const e=process.env.OPENROUTER_BASE_URL||u("openrouter")||"https://openrouter.ai/api/v1";return e.endsWith("/v1")?e:e.endsWith("/")?`${e}v1`:`${e}/v1`}if("ollama"===e){const e=process.env.OLLAMA_BASE_URL||u("ollama")||"http://localhost:11434/v1";return e.endsWith("/v1")?e:e.endsWith("/")?`${e}v1`:`${e}/v1`}if("ollama-cloud"===e){const e=process.env.OLLAMA_CLOUD_BASE_URL||process.env.OLLAMA_BASE_URL||u("ollama-cloud")||"http://localhost:11434/v1";return e.endsWith("/v1")?e:e.endsWith("/")?`${e}v1`:`${e}/v1`}if("zai"===e){const e=process.env.ZAI_BASE_URL||u("zai")||"https://api.z.ai/api/coding/paas/v4";return e.endsWith("/")?e.slice(0,-1):e}if("gemini-api"===e||"gemini-google"===e){const t=("gemini-api"===e?process.env.GEMINI_BASE_URL||process.env.GEMINI_API_BASE_URL:process.env.GEMINI_GOOGLE_BASE_URL||process.env.GEMINI_BASE_URL)||u(e)||"https://generativelanguage.googleapis.com/v1beta/openai";return t.endsWith("/")?t.slice(0,-1):t}if("nvidia"===e){const e=process.env.NVIDIA_BASE_URL||u("nvidia")||"https://integrate.api.nvidia.com/v1";return e.endsWith("/")?e.slice(0,-1):e}if("custom-openai"===e){const e=u("custom-openai")||"https://api.openai.com/v1";return e.endsWith("/")?e.slice(0,-1):e}const t=process.env.OPENAI_API_BASE_URL||process.env.OPENAI_BASE_URL||"https://api.openai.com/v1";return t.endsWith("/v1")?t:t.endsWith("/")?`${t}v1`:`${t}/v1`}async function getOpenAIRequestHeaders(e=getOpenAICompatibleProvider()){return"gemini-google"===e?n():function(e=getOpenAICompatibleProvider()){const t=r(e);if(isLocalOllamaProviderHost(e,getOpenAIBaseUrl(e)))return{"Content-Type":"application/json"};if(!t)throw new Error(`${getOpenAICompatibleProviderLabel(e)} is selected but no credentials were found.`);return{Authorization:`Bearer ${t}`,"Content-Type":"application/json"}}(e)}function isLocalOllamaProviderHost(e,t=getOpenAIBaseUrl(e)){return("ollama"===e||"ollama-cloud"===e)&&(t.includes("localhost")||t.includes("127.0.0.1"))}function getOpenAIAccessTokenOrThrow(e=getOpenAICompatibleProvider()){if(isLocalOllamaProviderHost(e))return"ollama";if("gemini-google"===e)return r(e)||"google-application-default-credentials";const t=r(e);if(!t)throw new Error(`${getOpenAICompatibleProviderLabel(e)} is selected but no credentials were found.`);return t}async function maybeRefreshOpenAICompatibleAuth(e=getOpenAICompatibleProvider()){"openai"===e&&await o()}async function maybeRecoverOpenAICompatible401(e,t=getOpenAICompatibleProvider()){if("openai"!==t)return null;if(!await i(e))return null;const o=s();return o&&o!==e?o:null}function toInputText(e){return{type:"input_text",text:e}}function toOutputText(e){return{type:"output_text",text:e}}function normalizeBlocksForRole(e,t){return"assistant"!==t?e:e.map(e=>"input_text"===e.type?toOutputText(e.text):e)}function stringifyBlockContent(e){return"string"==typeof e?e:Array.isArray(e)?e.map(e=>"string"==typeof e?e:e&&"object"==typeof e&&"type"in e&&"text"===e.type&&"text"in e&&"string"==typeof e.text?e.text:y(e)).join("\n"):null==e?"":y(e)}function normalizeResponseContent(e){return Array.isArray(e)?e:null==e?[]:[e]}function blockToOpenAIContentBlocks(e){if(!isRecord(e))return null;if("text"===e.type&&"string"==typeof e.text)return[toInputText(e.text)];if("image"===e.type){const t=isRecord(e.source)?e.source:null,o=t?function(e){if("base64"===e.type){const t=e.media_type,o=e.data;return"string"!=typeof t||"string"!=typeof o?null:{type:"input_image",image_url:`data:${t};base64,${o}`}}return"url"===e.type&&"string"==typeof e.url?{type:"input_image",image_url:e.url}:"file"===e.type&&"string"==typeof e.file_id?{type:"input_image",file_id:e.file_id}:null}(t):null;return o?[o]:null}if("document"===e.type){const t=isRecord(e.source)?e.source:null;if(!t)return null;const o=function(e,t){return"file"===e.type&&"string"==typeof e.file_id?{type:"input_file",file_id:e.file_id}:"base64"===e.type&&"string"==typeof e.data?"string"!=typeof e.media_type?null:{type:"input_file",file_data:e.data,..."string"==typeof t&&t?{filename:t}:{}}:"url"===e.type&&"string"==typeof e.url?{type:"input_file",file_url:e.url,..."string"==typeof t&&t?{filename:t}:{}}:"text"===e.type&&"string"==typeof e.data?toInputText(e.data):null}(t,"string"==typeof e.title?e.title:void 0);if(o)return[o];if("content"===t.type&&"string"==typeof t.content)return[toInputText(t.content)];if("content"===t.type&&Array.isArray(t.content)){const e=[];for(const o of t.content){const t=blockToOpenAIContentBlocks(o);t&&e.push(...t)}return e.length>0?e:null}return null}if("search_result"===e.type&&Array.isArray(e.content)){const t=[];"string"==typeof e.title&&e.title.trim()&&t.push(e.title.trim()),"string"==typeof e.source&&e.source.trim()&&t.push(e.source.trim());for(const o of e.content)if(o&&"object"==typeof o&&"text"in o){const e=o.text;"string"==typeof e&&e.trim()&&t.push(e.trim())}return[toInputText(t.join("\n\n"))]}if("container_upload"===e.type&&"string"==typeof e.file_id)return[{type:"input_file",file_id:e.file_id}];if(("bash_code_execution_output"===e.type||"mcp_tool_result"===e.type||"code_execution_tool_result"===e.type||"web_search_tool_result"===e.type||"web_fetch_tool_result"===e.type||"text_editor_code_execution_tool_result"===e.type||"tool_search_tool_result"===e.type)&&"content"in e){const t=e.content;if("string"==typeof t)return[toInputText(t)];if(Array.isArray(t)){const e=[];for(const o of t){const t=blockToOpenAIContentBlocks(o);t&&e.push(...t)}return e.length>0?e:null}}if("content"in e&&("string"==typeof e.content||Array.isArray(e.content))){const t=e.content;if("string"==typeof t)return[toInputText(t)];const o=[];for(const e of t){const t=blockToOpenAIContentBlocks(e);t&&o.push(...t)}return o.length>0?o:null}return"data"in e&&"string"==typeof e.data?[toInputText(e.data)]:null}function toolResultContentToOpenAIOutput(e){if("string"==typeof e)return e;if(!Array.isArray(e))return stringifyBlockContent(e);const t=[];for(const o of e){const e=blockToOpenAIContentBlocks(o);if(e&&e.length>0){t.push(...e);continue}const n=stringifyBlockContent(o).trim();n&&t.push(toInputText(n))}return 0===t.length?"":t.every(e=>"input_text"===e.type)?t.map(e=>e.text).join("\n\n"):t}function messageToOpenAIInput(e){if(!e.message||"user"!==e.type&&"assistant"!==e.type)return[];const t=Array.isArray(e.message.content)?e.message.content:[{type:"text",text:String(e.message.content??"")}],o="assistant"===e.type?"assistant":"user",n=[],r=[],flushMessage=()=>{0!==r.length&&(n.push({type:"message",role:o,content:[...r]}),r.length=0)};for(const s of t){if("assistant"===e.type&&"tool_use"===s.type&&"string"==typeof s.id&&"string"==typeof s.name){flushMessage(),n.push({type:"function_call",call_id:s.id,name:s.name,arguments:y(s.input??{})});continue}if("user"===e.type&&"tool_result"===s.type&&"string"==typeof s.tool_use_id){flushMessage(),n.push({type:"function_call_output",call_id:s.tool_use_id,output:toolResultContentToOpenAIOutput(s.content)});continue}if("thinking"===s.type||"redacted_thinking"===s.type)continue;const t=blockToOpenAIContentBlocks(s);t&&t.length>0?r.push(...normalizeBlocksForRole(t,o)):r.push(..."assistant"===o?[toOutputText(stringifyBlockContent(s))]:[toInputText(stringifyBlockContent(s))])}return flushMessage(),n}async function readOpenAIResponseBody(e){const t=await e.text();if(!t.trim())return{};const o=t.trim();if(o.startsWith("data:")||o.startsWith("event:"))return function(e){const t=[];for(const o of e.split(/\r?\n\r?\n/)){const e=o.split(/\r?\n/).map(e=>e.trim()).filter(Boolean);if(0===e.length)continue;const n=e.filter(e=>e.startsWith("data:")).map(e=>e.slice(5).trim());if(0===n.length)continue;const r=n.join("\n").trim();if(r&&"[DONE]"!==r)try{const e=JSON.parse(r);isRecord(e)&&t.push(e)}catch{}}let o=null,n=null;const r=[];let s="";for(const i of t){const t="string"==typeof i.type?i.type:"";"response.completed"===t&&isRecord(i.response)?o={...i.response,raw_error_text:e}:"error"!==t?"response.output_item.done"===t&&isRecord(i.item)?r.push(i.item):"response.output_text.delta"!==t||"string"!=typeof i.delta?"response.output_text.done"===t&&"string"==typeof i.text&&(s=i.text):s+=i.delta:"string"==typeof i.message&&i.message.trim()?n=i.message:isRecord(i.error)&&"string"==typeof i.error.message&&(n=i.error.message)}if(o)return(!o.output||0===o.output.length)&&r.length>0&&(o.output=r),!o.output_text&&s&&(o.output_text=s),!o.error&&n&&(o.error={message:n}),o;if(r.length>0||s||n)return{output:r.length>0?r:void 0,output_text:s||void 0,error:n?{message:n}:void 0,raw_error_text:e};return{error:{message:e},raw_error_text:e}}(t);try{const e=JSON.parse(t);return isRecord(e)&&"string"==typeof e.error?{...e,error:{message:e.error},raw_error_text:t}:isRecord(e)?{...e,raw_error_text:t}:{error:{message:t},raw_error_text:t}}catch{return{error:{message:t},raw_error_text:t}}}function buildOpenAIErrorMessage(e){const t=e.data.error?.message?.trim()||e.data.raw_error_text?.trim()||`OpenAI request failed (${e.status} ${e.statusText})`,o=/requires a subscription|upgrade for access/i.test(t)?`El modelo ${e.model??"seleccionado"} requiere una suscripcion de Ollama Cloud. Cambia a otro modelo en /model o actualiza tu plan de Ollama.`:t,n=e.data.raw_error_text?.trim(),r=n&&n!==t&&n!==o?n.replace(/\s+/g," ").slice(0,400):null;return r?`${o} [model=${e.model??"unknown"} endpoint=${e.url}] ${r}`:`${o} [model=${e.model??"unknown"} endpoint=${e.url}]`}function blockToChatContentPart(e){if("text"===e.type&&"string"==typeof e.text)return{type:"text",text:e.text};if("image"===e.type){const t=isRecord(e.source)?e.source:null;if(!t)return null;if("base64"===t.type&&"string"==typeof t.data&&"string"==typeof t.media_type)return{type:"image_url",image_url:{url:`data:${t.media_type};base64,${t.data}`}};if("url"===t.type&&"string"==typeof t.url)return{type:"image_url",image_url:{url:t.url}}}const t=stringifyBlockContent(e);return t?{type:"text",text:t}:null}function toolResultToString(e){return"string"==typeof e?e:Array.isArray(e)?e.map(e=>"string"==typeof e?e:isRecord(e)&&"string"==typeof e.text?e.text:stringifyBlockContent(e)).filter(Boolean).join("\n"):stringifyBlockContent(e)}function messageToChatMessages(e){if(!e.message||"user"!==e.type&&"assistant"!==e.type)return[];const t=e.message.content,o=Array.isArray(t)?t:[{type:"text",text:String(t??"")}];if("assistant"===e.type){const e=[],t=[];for(const n of o)"thinking"!==n.type&&"redacted_thinking"!==n.type&&("tool_use"===n.type&&"string"==typeof n.id&&"string"==typeof n.name?e.push({id:n.id,type:"function",function:{name:n.name,arguments:y(n.input??{})}}):"text"===n.type&&"string"==typeof n.text&&n.text.trim()&&t.push(n.text));const n={role:"assistant",content:t.join("\n")};return e.length>0&&(n.tool_calls=e),[n]}const n=[],r=[];for(const e of o)if("tool_result"===e.type&&"string"==typeof e.tool_use_id)n.push({role:"tool",tool_call_id:e.tool_use_id,content:toolResultToString(e.content)});else{const t=blockToChatContentPart(e);t&&r.push(t)}const s=[...n];if(r.length>0){const e=r.every(e=>"text"===e.type);s.push({role:"user",content:e?r.map(e=>e.text).join("\n"):r})}return s}function parseChatCompletionResponse(e){const t=[];for(const o of e.choices??[]){const e=o.message;if(e){"string"==typeof e.content&&e.content.trim()&&t.push({type:"text",text:e.content});for(const o of e.tool_calls??[])t.push({type:"tool_use",id:o.id,name:o.function?.name??"tool",input:parseFunctionCallArguments(o.function?.arguments)})}}return{content:t}}function getChatUsage(e){if("number"==typeof e.usage?.prompt_tokens||"number"==typeof e.usage?.completion_tokens)return{input_tokens:e.usage?.prompt_tokens??0,output_tokens:e.usage?.completion_tokens??0}}function buildChatToolChoice(e){if(!e.toolChoice)return"auto";switch(e.toolChoice.type){case"auto":default:return"auto";case"any":return"required";case"none":return"none";case"tool":return"string"==typeof e.toolChoice.name?{type:"function",function:{name:e.toolChoice.name}}:"auto"}}function chatContentToGeminiParts(e){return"string"==typeof e?e?[{text:e}]:[]:Array.isArray(e)?e.map(e=>"text"===e.type?e.text?{text:e.text}:null:"image_url"===e.type?{text:`[Image input: ${e.image_url.url}]`}:null).filter(e=>null!==e):[]}function buildGeminiContents(e){const t=new Map,o=[];for(const n of e){if("system"===n.role)continue;if("assistant"===n.role){const e=chatContentToGeminiParts(n.content);for(const o of n.tool_calls??[]){t.set(o.id,o.function.name);const n=parseFunctionCallArguments(o.function.arguments);e.push({functionCall:{name:o.function.name,args:isPlainObject(n)?n:{raw:n}}})}e.length>0&&o.push({role:"model",parts:e});continue}if("tool"===n.role){const e=n.tool_call_id?t.get(n.tool_call_id)??"tool":"tool";o.push({role:"function",parts:[{functionResponse:{name:e,response:{result:n.content??""}}}]});continue}const e=chatContentToGeminiParts(n.content);e.length>0&&o.push({role:"user",parts:e})}return o.length>0?o:[{role:"user",parts:[{text:""}]}]}function getGeminiEnumType(e){switch(typeof e){case"string":return"string";case"number":return Number.isInteger(e)?"integer":"number";case"boolean":return"boolean";default:return}}function sanitizeGeminiSchema(e){if(!isRecord(e))return{type:"object",properties:{}};const t=Array.isArray(e.anyOf)?e.anyOf:Array.isArray(e.any_of)?e.any_of:null,o=Array.isArray(e.oneOf)?e.oneOf:Array.isArray(e.one_of)?e.one_of:null;if(t||o){const e=function(e){const t=[];let o,n=!1;for(const r of e){if(!isRecord(r))return null;if("null"===r.type){n=!0;continue}const e=void 0!==r.const?[r.const]:Array.isArray(r.enum)?r.enum:null;if(!e)return null;for(const n of e){const e=getGeminiEnumType(n);if(!e)return null;if(o&&o!==e)return null;o=e,t.push(n)}}return o&&0!==t.length?{type:o,enum:Array.from(new Set(t)),...n?{nullable:!0}:{}}:null}(t??o??[]);return e||{anyOf:(t??o??[]).map(sanitizeGeminiSchema)}}const n={},r=e.type;if(Array.isArray(r)){const e=r.find(e=>"null"!==e);"string"==typeof e&&(n.type=e),r.includes("null")&&(n.nullable=!0)}else"string"==typeof r&&(n.type=r);for(const t of["title","description","format","nullable","minimum","maximum","minItems","maxItems","minLength","maxLength","pattern"])void 0!==e[t]&&(n[t]=e[t]);if(Array.isArray(e.enum)?n.enum=e.enum:void 0!==e.const&&(n.enum=[e.const]),!n.type&&Array.isArray(n.enum)&&n.enum.length>0&&(n.type=getGeminiEnumType(n.enum[0])),void 0!==e.exclusiveMinimum&&void 0===n.minimum&&(n.minimum="number"==typeof e.exclusiveMinimum?e.exclusiveMinimum:e.minimum),void 0!==e.exclusiveMaximum&&void 0===n.maximum&&(n.maximum="number"==typeof e.exclusiveMaximum?e.exclusiveMaximum:e.maximum),isRecord(e.items)?n.items=sanitizeGeminiSchema(e.items):Array.isArray(e.items)&&e.items.length>0&&(n.items=sanitizeGeminiSchema(e.items[0])),isRecord(e.properties)){const t={};for(const[o,n]of Object.entries(e.properties))t[o]=sanitizeGeminiSchema(n);n.properties=t}return Array.isArray(e.required)&&(n.required=e.required.filter(e=>"string"==typeof e)),n.type||(n.type=n.properties?"object":n.items?"array":"object"),"object"!==n.type||n.properties||(n.properties={}),n}async function postGeminiCodeAssist(e,t,o,n){const r=await fetch(`https://cloudcode-pa.googleapis.com/v1internal:${e}`,{method:"POST",headers:t,body:y(o),signal:n});return{response:r,data:await readOpenAIResponseBody(r)}}function getGeminiCodeAssistMetadata(e){return{ideType:"IDE_UNSPECIFIED",platform:"PLATFORM_UNSPECIFIED",pluginType:"GEMINI",...e?{duetProject:e}:{}}}async function resolveGeminiCodeAssistProject(e,t){const o=process.env.GEMINI_GOOGLE_PROJECT_ID?.trim()||void 0,n={...o?{cloudaicompanionProject:o}:{},metadata:getGeminiCodeAssistMetadata(o)},{response:r,data:s}=await postGeminiCodeAssist("loadCodeAssist",e,n,t);if(!r.ok)return o;if("string"==typeof s.cloudaicompanionProject)return s.cloudaicompanionProject;if(o)return o;const i=Array.isArray(s.allowedTiers)?s.allowedTiers.filter(isRecord):[],a=i.find(e=>!0===e.isDefault)??i[0],u="string"==typeof a?.id?a.id:void 0;if(!u)return;const{response:l,data:p}=await postGeminiCodeAssist("onboardUser",e,{tierId:u,metadata:getGeminiCodeAssistMetadata()},t);if(!l.ok)return;const c=isRecord(p.response)?p.response:p,m=isRecord(c.cloudaicompanionProject)?c.cloudaicompanionProject:null;return"string"==typeof m?.id?m.id:void 0}async function createGeminiGoogleChatCompletionResponse(e){const{model:o,chatMessages:r,chatTools:s,toolChoice:i,signal:a,maxOutputTokens:u,temperature:l}=e,c=await n(),m=await resolveGeminiCodeAssistProject(c,a),d={};u&&(d.maxOutputTokens=u),void 0!==l&&(d.temperature=l);const f={contents:buildGeminiContents(r),session_id:t()},g=r.filter(e=>"system"===e.role&&"string"==typeof e.content).map(e=>e.content).join("\n\n");g&&(f.systemInstruction={role:"user",parts:[{text:g}]});const h=function(e){if(0!==e.length)return[{functionDeclarations:e.map(e=>({name:e.function.name,description:e.function.description,parameters:sanitizeGeminiSchema(e.function.parameters??{type:"object",properties:{}})}))}]}(s);h&&(f.tools=h);const _=function(e){if("auto"!==e)return"none"===e?{functionCallingConfig:{mode:"NONE"}}:"required"===e?{functionCallingConfig:{mode:"ANY"}}:{functionCallingConfig:{mode:"ANY",allowedFunctionNames:[e.function.name]}}}(i);_&&(f.toolConfig=_),Object.keys(d).length>0&&(f.generationConfig=d);const A={model:o,...m?{project:m}:{},user_prompt_id:t(),request:f},O="https://cloudcode-pa.googleapis.com/v1internal:generateContent";p(`[Gemini Google] codeassist generateContent request model=${o} messages=${r.length} tools=${s.length} endpoint=${O}`);const{response:b,data:x}=await postGeminiCodeAssist("generateContent",c,A,a);if(!b.ok)throw p(`[Gemini Google] codeassist generateContent error status=${b.status} model=${o} endpoint=${O} body=${(x.error?.message??"").replace(/\s+/g," ").slice(0,500)}`,{level:"error"}),new Error(buildOpenAIErrorMessage({status:b.status,statusText:b.statusText,url:O,model:o,data:x}));return function(e){const o=e.response?.candidates??[];return{id:e.traceId,choices:o.map(e=>{const o=[],n=[];for(const r of e.content?.parts??[])"text"in r&&"string"==typeof r.text&&o.push(r.text),"functionCall"in r&&r.functionCall?.name&&n.push({id:`call_${t().replace(/-/g,"")}`,type:"function",function:{name:r.functionCall.name,arguments:y(r.functionCall.args??{})}});return{message:{content:o.join("")||null,tool_calls:n.length>0?n:void 0},finish_reason:e.finishReason}}),usage:{prompt_tokens:e.response?.usageMetadata?.promptTokenCount,completion_tokens:e.response?.usageMetadata?.candidatesTokenCount}}}(x)}async function buildOpenAITools(e,t){return(await Promise.all(e.map(o=>g(o,{getToolPermissionContext:t.getToolPermissionContext,tools:e,agents:t.agents,allowedAgentTypes:t.allowedAgentTypes,model:t.model})))).map(e=>({type:"function",name:e.name,description:e.description,parameters:e.input_schema,...e.strict?{strict:!0}:{}}))}function buildToolChoice(e){if(!e.toolChoice)return"auto";switch(e.toolChoice.type){case"auto":default:return"auto";case"any":return"required";case"none":return"none";case"tool":return"string"==typeof e.toolChoice.name?{type:"function",name:e.toolChoice.name}:"auto"}}function shouldDisableParallelToolCalls(e){const t=e.toolChoice;return Boolean(t&&"disable_parallel_tool_use"in t&&!0===t.disable_parallel_tool_use)}function parseFunctionCallArguments(e){if(isPlainObject(e))return e;if("string"!=typeof e)return null==e?{}:{raw:e};try{const t=JSON.parse(e);return isPlainObject(t)?t:{raw:t}}catch{return{raw:e}}}function parseOutputItems(e){const t=[];for(const o of e.output??[])if(o&&"object"==typeof o){if("function_call"===o.type){const e=parseFunctionCallArguments(o.arguments);t.push({type:"tool_use",id:String(o.call_id??o.id??""),name:String(o.name??"tool"),input:e});continue}if("message"===o.type)for(const e of normalizeResponseContent(o.content)){if("string"==typeof e){t.push({type:"text",text:e});continue}if(!e||"object"!=typeof e||!("type"in e))continue;const o=String(e.type??""),n="string"==typeof e.text?e.text??"":"string"==typeof e.refusal?e.refusal??"":"";"output_text"!==o&&"text"!==o&&"refusal"!==o||!n||t.push({type:"text",text:n})}}return 0===t.length&&"string"==typeof e.output_text&&t.push({type:"text",text:e.output_text}),{content:t}}function getUsage(e){if("number"==typeof e.usage?.input_tokens||"number"==typeof e.usage?.output_tokens)return{input_tokens:e.usage?.input_tokens??0,output_tokens:e.usage?.output_tokens??0}}function sideQueryMessageToOpenAIInput(e){const t=Array.isArray(e.content)?e.content.filter(e=>"text"===e?.type&&"string"==typeof e.text).map(e=>toInputText(e.text)):[toInputText(String(e.content??""))];return[{type:"message",role:e.role,content:t.length>0?t:[toInputText("")]}]}function sideQueryToolToOpenAITool(e){return{type:"function",name:e.name,description:e.description,parameters:e.input_schema??{type:"object",properties:{}}}}function buildSideQueryToolChoice(e){return e&&"auto"!==e?"none"===e||"none"===e.type?"none":"any"===e.type?"required":"auto"===e.type?"auto":"string"==typeof e.name&&e.name?{type:"function",name:e.name}:"auto":"auto"}function sideQueryMessageToChatMessage(e){const t=Array.isArray(e.content)?e.content.filter(e=>"text"===e?.type&&"string"==typeof e.text).map(e=>e.text).join("\n"):String(e.content??"");return{role:e.role,content:t}}function sideQueryToolToChatTool(e){return{type:"function",function:{name:e.name,description:e.description,parameters:e.input_schema??{type:"object",properties:{}}}}}export async function queryOpenAISideQuery({model:e,systemPrompt:t,messages:o,tools:n,toolChoice:s,outputFormat:i,signal:a,maxOutputTokens:u,temperature:l}){const c=getOpenAICompatibleProvider();await maybeRefreshOpenAICompatibleAuth(c);const m=getOpenAIBaseUrl(c),d=r(c);if(!("openai"===c&&d&&isJwtToken(d))){const r=[...t?[{role:"system",content:t}]:[],...o.map(sideQueryMessageToChatMessage)],d={model:e,messages:r,stream:!1},f=n?.map(sideQueryToolToChatTool)??[],g=function(e){const t=buildSideQueryToolChoice(e);return"auto"===t||"none"===t?t:"required"===t?"required":{type:"function",function:{name:t.name}}}(s);if(f.length>0&&(d.tools=f,d.tool_choice=g),"json_schema"===i?.type&&(d.response_format={type:"json_schema",json_schema:{name:"side_query_output",strict:!0,schema:i.schema}}),u&&(d.max_tokens=u),void 0!==l&&(d.temperature=l),"gemini-google"===c){const t=await createGeminiGoogleChatCompletionResponse({model:e,chatMessages:r,chatTools:f,toolChoice:g,signal:a,maxOutputTokens:u,temperature:l});return{id:t.id,content:parseChatCompletionResponse(t).content,usage:getChatUsage(t)}}const h=`${m}/chat/completions`,_=await fetch(h,{method:"POST",headers:await getOpenAIRequestHeaders(c),body:y(d),signal:a}),A=await readOpenAIResponseBody(_);if(!_.ok)throw p(`[${getOpenAICompatibleProviderLabel(c)}] sideQuery chat.completions error status=${_.status} model=${e} endpoint=${h} body=${(A.error?.message??"").replace(/\s+/g," ").slice(0,500)}`,{level:"error"}),new Error(buildOpenAIErrorMessage({status:_.status,statusText:_.statusText,url:h,model:e,data:A}));return{id:A.id,content:parseChatCompletionResponse(A).content,usage:getChatUsage(A)}}const f={model:e,input:o.flatMap(sideQueryMessageToOpenAIInput),instructions:t,stream:!1,store:!1};n&&n.length>0&&(f.tools=n.map(sideQueryToolToOpenAITool),f.tool_choice=buildSideQueryToolChoice(s)),"json_schema"===i?.type&&(f.text={format:{type:"json_schema",name:"side_query_output",strict:!0,schema:i.schema}}),u&&(f.max_output_tokens=u),void 0!==l&&(f.temperature=l);const g=`${m}/responses`,h=await fetch(g,{method:"POST",headers:await getOpenAIRequestHeaders(c),body:y(f),signal:a}),_=await readOpenAIResponseBody(h);if(!h.ok)throw p(`[${getOpenAICompatibleProviderLabel(c)}] sideQuery error status=${h.status} model=${e} endpoint=${m}/responses body=${(_.raw_error_text??"").replace(/\s+/g," ").slice(0,500)}`,{level:"error"}),new Error(buildOpenAIErrorMessage({status:h.status,statusText:h.statusText,url:`${m}/responses`,model:e,data:_}));return{id:_.id,content:parseOutputItems(_).content,usage:getUsage(_)}}async function createOpenAIResponse(e){const{messages:t,systemPrompt:o,tools:n,signal:s,options:i}=e,a=getOpenAICompatibleProvider();await maybeRefreshOpenAICompatibleAuth(a);const u=getOpenAIAccessTokenOrThrow(a),l="openai"===a&&isJwtToken(u);if(!l){const t=await async function({messages:e,systemPrompt:t,tools:o,signal:n,options:s}){const i=getOpenAICompatibleProvider();await maybeRefreshOpenAICompatibleAuth(i);const a=t.join("\n\n"),u=[...a?[{role:"system",content:a}]:[],...e.flatMap(messageToChatMessages)],l=(m=await buildOpenAITools(o,s),m.map(e=>({type:"function",function:{name:e.name,description:e.description,parameters:e.parameters,...e.strict?{strict:!0}:{}}}))),c={model:s.model,messages:u,stream:!1};var m;if(l.length>0&&(c.tools=l,c.tool_choice=buildChatToolChoice(s)),shouldDisableParallelToolCalls(s)&&(c.parallel_tool_calls=!1),s.maxOutputTokensOverride&&(c.max_tokens=s.maxOutputTokensOverride),void 0!==s.temperatureOverride&&(c.temperature=s.temperatureOverride),s.effortValue&&(c.reasoning_effort=s.effortValue),"gemini-google"===i)return createGeminiGoogleChatCompletionResponse({model:String(s.model),chatMessages:u,chatTools:l,toolChoice:buildChatToolChoice(s),signal:n,maxOutputTokens:s.maxOutputTokensOverride,temperature:s.temperatureOverride});const d=getOpenAIMaxTimeoutRetries(),sendRequest=async(e=r(i)??"",t=0)=>{const o=`${getOpenAIBaseUrl(i)}/chat/completions`;p(`[${getOpenAICompatibleProviderLabel(i)}] chat.completions request model=${s.model} messages=${u.length} tools=${l.length} endpoint=${o}${t>0?` (retry ${t})`:""}`);const a=12e4,m=new AbortController,f=setTimeout(()=>m.abort(),a),onAbort=()=>m.abort();n?.addEventListener("abort",onAbort);try{const n=await fetch(o,{method:"POST",headers:await getOpenAIRequestHeaders(i),body:y(c),signal:m.signal}),r=await readOpenAIResponseBody(n);if(504===n.status&&t<1)return p(`[${getOpenAICompatibleProviderLabel(i)}] 504 Gateway Timeout, reintentando...`,{level:"warn"}),sendRequest(e,t+1);if(401===n.status){const o=await maybeRecoverOpenAICompatible401(e,i);if(o)return sendRequest(o,t)}if(!n.ok)throw p(`[${getOpenAICompatibleProviderLabel(i)}] chat.completions error status=${n.status} model=${s.model} endpoint=${o} body=${(r.error?.message??"").replace(/\s+/g," ").slice(0,500)}`,{level:"error"}),new Error(buildOpenAIErrorMessage({status:n.status,statusText:n.statusText,url:o,model:String(s.model),data:r}));return r}catch(o){if(o instanceof Error&&"AbortError"===o.name&&!n?.aborted){if(t<d){const o=1e3*Math.pow(2,t);return p(`[${getOpenAICompatibleProviderLabel(i)}] timeout local tras 120000ms, reintentando en ${o}ms (intento ${t+1}/${d})`,{level:"warn"}),await new Promise(e=>setTimeout(e,o)),sendRequest(e,t+1)}throw new Error("La solicitud expiró tras 120s. El servidor tardó demasiado en responder.")}throw o}finally{clearTimeout(f),n?.removeEventListener("abort",onAbort)}};return getOpenAIAccessTokenOrThrow(i),sendRequest()}(e);return{id:t.id,output:t.choices?.flatMap(e=>{const t=[];if(e.message?.content&&t.push({type:"message",role:"assistant",content:[e.message.content]}),e.message?.tool_calls)for(const o of e.message.tool_calls)t.push({type:"function_call",call_id:o.id,name:o.function.name,arguments:o.function.arguments});return t})??[],usage:{input_tokens:t.usage?.prompt_tokens,output_tokens:t.usage?.completion_tokens}}}const c=t.flatMap(messageToOpenAIInput),m=await buildOpenAITools(n,i),d={model:i.model,input:c,instructions:o.join("\n\n"),tools:m,tool_choice:buildToolChoice(i),stream:!1,store:!1};shouldDisableParallelToolCalls(i)&&(d.parallel_tool_calls=!1),i.maxOutputTokensOverride&&(d.max_output_tokens=i.maxOutputTokensOverride),void 0!==i.temperatureOverride&&(d.temperature=i.temperatureOverride),i.effortValue&&(d.reasoning={effort:i.effortValue});const f=getOpenAIMaxTimeoutRetries(),sendRequest=async(e,t=0)=>{const o=l?{...d,stream:!0}:d;let n,r;if(l){const t=function(e){try{const t=JSON.parse(atob(e.split(".")[1])),o=t?.["https://api.openai.com/auth"]?.chatgpt_account_id;if(!o)throw new Error("No account ID in token");return o}catch{throw new Error("Failed to extract chatgpt-account-id from OAuth token")}}(e);n=function(){const e=(process.env.OPENAI_OAUTH_BASE_URL||"https://chatgpt.com/backend-api").replace(/\/+$/,"");return e.endsWith("/codex/responses")?e:e.endsWith("/codex")?`${e}/responses`:`${e}/codex/responses`}(),r={Authorization:`Bearer ${e}`,"chatgpt-account-id":t,"OpenAI-Beta":"responses=experimental",originator:"pi","content-type":"application/json",accept:"application/json"}}else n=`${getOpenAIBaseUrl(a)}/responses`,r={Authorization:`Bearer ${e}`,"Content-Type":"application/json"};const u=12e4,c=new AbortController,m=setTimeout(()=>c.abort(),u),onAbort=()=>c.abort();s?.addEventListener("abort",onAbort);try{const s=await fetch(n,{method:"POST",headers:r,body:y(o),signal:c.signal}),u=await readOpenAIResponseBody(s);if(504===s.status&&t<1)return p(`[${getOpenAICompatibleProviderLabel(a)}] responses 504 Gateway Timeout, reintentando...`,{level:"warn"}),sendRequest(e,t+1);if(401===s.status){const o=await maybeRecoverOpenAICompatible401(e,a);if(o)return sendRequest(o,t)}if(!s.ok)throw p(`[${getOpenAICompatibleProviderLabel(a)}] responses error status=${s.status} model=${i.model} endpoint=${n} oauth=${l} body=${(u.raw_error_text??"").replace(/\s+/g," ").slice(0,500)}`,{level:"error"}),new Error(buildOpenAIErrorMessage({status:s.status,statusText:s.statusText,url:n,model:String(i.model),data:u}));return u}catch(o){if(o instanceof Error&&"AbortError"===o.name&&!s?.aborted){if(t<f){const o=1e3*Math.pow(2,t);return p(`[${getOpenAICompatibleProviderLabel(a)}] responses timeout local tras 120000ms, reintentando en ${o}ms (intento ${t+1}/${f})`,{level:"warn"}),await new Promise(e=>setTimeout(e,o)),sendRequest(e,t+1)}throw new Error("La solicitud expiró tras 120s. El servidor tardó demasiado en responder.")}throw o}finally{clearTimeout(m),s?.removeEventListener("abort",onAbort)}};return sendRequest(u)}export async function*queryOpenAIModelWithStreaming({messages:t,systemPrompt:o,thinkingConfig:n,tools:r,signal:s,options:i}){try{for(let e=1;e<=2;e++){const n=await createOpenAIResponse({messages:1===e?t:[...t,f({content:"System reminder: your previous response for this turn was empty. Continue the current task without asking the user to repeat themselves. If a tool call is needed, emit the appropriate tool call now. Do not return an empty response.",isMeta:!0})],systemPrompt:o,tools:r,signal:s,options:i}),{content:a}=parseOutputItems(n);if(a.length>0)return void(yield d({content:a,usage:getUsage(n)}));if(!(e<2))return void(yield m({content:"OpenAI returned no content after retrying."}));p(`[${getOpenAICompatibleProviderLabel(getOpenAICompatibleProvider())}] empty model response with no content; retrying request (${e}/1)`,{level:"warn"})}}catch(t){if(s.aborted)throw new e;c(t),yield m({content:l(t),errorDetails:l(t)})}}
1
+ import{APIUserAbortError as e}from"@anthropic-ai/sdk/error.js";import{randomUUID as t}from"node:crypto";import{checkAndRefreshOpenAIOAuthTokenIfNeeded as n,getGeminiGoogleAuthHeaders as o,getOpenAICompatibleAccessToken as r,getOpenAIAccessToken as s,handleOpenAIOAuth401Error as i}from"../../utils/auth.js";import{getAPIProvider as a,isOpenAICompatibleProvider as u}from"../../utils/model/providers.js";import{getConfiguredProviderBaseUrl as l}from"../../utils/model/providerBaseUrls.js";import{getOpenAIOriginator as c}from"../../constants/oauth.js";import{errorMessage as p}from"../../utils/errors.js";import{logForDebugging as m}from"../../utils/debug.js";import{logError as d}from"../../utils/log.js";import{createAssistantAPIErrorMessage as f,createAssistantMessage as g,createUserMessage as y}from"../../utils/messages.js";import{addToTotalSessionCost as h}from"../../cost-tracker.js";import{calculateUSDCost as _}from"../../utils/modelCost.js";import{toolToAPISchema as A}from"../../utils/api.js";import{jsonStringify as O}from"../../utils/slowOperations.js";function getOpenAIMaxTimeoutRetries(){const e=process.env.CONTEXT_CODE_MAX_RETRIES;if(!e)return 10;const t=Number.parseInt(e,10);return!Number.isFinite(t)||t<0?10:t}function isRecord(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}function isPlainObject(e){if(!isRecord(e))return!1;const t=Object.getPrototypeOf(e);return t===Object.prototype||null===t}function isJwtToken(e){return 3===e.split(".").length}function getOpenAICompatibleProvider(){const e=a();return u(e)?e:"openai"}function getOpenAICompatibleProviderLabel(e=getOpenAICompatibleProvider()){switch(e){case"openrouter":return"OpenRouter";case"ollama":return"Ollama";case"ollama-cloud":return"Ollama Cloud";case"gemini-api":return"Gemini API";case"gemini-google":return"Gemini Google";case"zai":return"Z.AI";case"nvidia":return"NVIDIA NIM";case"custom-openai":return"Custom OpenAI";default:return"OpenAI"}}function getOpenAIBaseUrl(e=getOpenAICompatibleProvider()){if("openrouter"===e){const e=process.env.OPENROUTER_BASE_URL||l("openrouter")||"https://openrouter.ai/api/v1";return e.endsWith("/v1")?e:e.endsWith("/")?`${e}v1`:`${e}/v1`}if("ollama"===e){const e=process.env.OLLAMA_BASE_URL||l("ollama")||"http://localhost:11434/v1";return e.endsWith("/v1")?e:e.endsWith("/")?`${e}v1`:`${e}/v1`}if("ollama-cloud"===e){const e=process.env.OLLAMA_CLOUD_BASE_URL||process.env.OLLAMA_BASE_URL||l("ollama-cloud")||"http://localhost:11434/v1";return e.endsWith("/v1")?e:e.endsWith("/")?`${e}v1`:`${e}/v1`}if("zai"===e){const e=process.env.ZAI_BASE_URL||l("zai")||"https://api.z.ai/api/coding/paas/v4";return e.endsWith("/")?e.slice(0,-1):e}if("gemini-api"===e||"gemini-google"===e){const t=("gemini-api"===e?process.env.GEMINI_BASE_URL||process.env.GEMINI_API_BASE_URL:process.env.GEMINI_GOOGLE_BASE_URL||process.env.GEMINI_BASE_URL)||l(e)||"https://generativelanguage.googleapis.com/v1beta/openai";return t.endsWith("/")?t.slice(0,-1):t}if("nvidia"===e){const e=process.env.NVIDIA_BASE_URL||l("nvidia")||"https://integrate.api.nvidia.com/v1";return e.endsWith("/")?e.slice(0,-1):e}if("custom-openai"===e){let e=l("custom-openai")||"https://api.openai.com/v1";return e.startsWith("http://chinai.iaforged.com")&&(e=e.replace("http://chinai.iaforged.com","https://chinai.iaforged.com")),e.endsWith("/")?e.slice(0,-1):e}if("openai"!==e&&"custom-openai"!==e){const t=l(e);return t.endsWith("/")?t.slice(0,-1):t}const t=process.env.OPENAI_API_BASE_URL||process.env.OPENAI_BASE_URL||"https://api.openai.com/v1";return t.endsWith("/v1")?t:t.endsWith("/")?`${t}v1`:`${t}/v1`}async function getOpenAIRequestHeaders(e=getOpenAICompatibleProvider()){return"gemini-google"===e?o():function(e=getOpenAICompatibleProvider()){const t=r(e);if(isLocalOllamaProviderHost(e,getOpenAIBaseUrl(e)))return{"Content-Type":"application/json"};if(!t)throw new Error(`${getOpenAICompatibleProviderLabel(e)} is selected but no credentials were found.`);return"custom-openai"===e?{Authorization:`Bearer ${t}`,"X-API-Key":t,"api-key":t,"Content-Type":"application/json"}:{Authorization:`Bearer ${t}`,"Content-Type":"application/json"}}(e)}function isLocalOllamaProviderHost(e,t=getOpenAIBaseUrl(e)){return("ollama"===e||"ollama-cloud"===e)&&(t.includes("localhost")||t.includes("127.0.0.1"))}function getOpenAIAccessTokenOrThrow(e=getOpenAICompatibleProvider()){if(isLocalOllamaProviderHost(e))return"ollama";if("gemini-google"===e)return r(e)||"google-application-default-credentials";const t=r(e);if(!t)throw new Error(`${getOpenAICompatibleProviderLabel(e)} is selected but no credentials were found.`);return t}async function maybeRefreshOpenAICompatibleAuth(e=getOpenAICompatibleProvider()){"openai"===e&&await n()}async function maybeRecoverOpenAICompatible401(e,t=getOpenAICompatibleProvider()){if("openai"!==t)return null;if(!await i(e))return null;const n=s();return n&&n!==e?n:null}function toInputText(e){return{type:"input_text",text:e}}function toOutputText(e){return{type:"output_text",text:e}}function normalizeBlocksForRole(e,t){return"assistant"!==t?e:e.map(e=>"input_text"===e.type?toOutputText(e.text):e)}function stringifyBlockContent(e){return"string"==typeof e?e:Array.isArray(e)?e.map(e=>"string"==typeof e?e:e&&"object"==typeof e&&"type"in e&&"text"===e.type&&"text"in e&&"string"==typeof e.text?e.text:O(e)).join("\n"):null==e?"":O(e)}function normalizeResponseContent(e){return Array.isArray(e)?e:null==e?[]:[e]}function blockToOpenAIContentBlocks(e){if(!isRecord(e))return null;if("text"===e.type&&"string"==typeof e.text)return[toInputText(e.text)];if("image"===e.type){const t=isRecord(e.source)?e.source:null,n=t?function(e){if("base64"===e.type){const t=e.media_type,n=e.data;return"string"!=typeof t||"string"!=typeof n?null:{type:"input_image",image_url:`data:${t};base64,${n}`}}return"url"===e.type&&"string"==typeof e.url?{type:"input_image",image_url:e.url}:"file"===e.type&&"string"==typeof e.file_id?{type:"input_image",file_id:e.file_id}:null}(t):null;return n?[n]:null}if("document"===e.type){const t=isRecord(e.source)?e.source:null;if(!t)return null;const n=function(e,t){return"file"===e.type&&"string"==typeof e.file_id?{type:"input_file",file_id:e.file_id}:"base64"===e.type&&"string"==typeof e.data?"string"!=typeof e.media_type?null:{type:"input_file",file_data:e.data,..."string"==typeof t&&t?{filename:t}:{}}:"url"===e.type&&"string"==typeof e.url?{type:"input_file",file_url:e.url,..."string"==typeof t&&t?{filename:t}:{}}:"text"===e.type&&"string"==typeof e.data?toInputText(e.data):null}(t,"string"==typeof e.title?e.title:void 0);if(n)return[n];if("content"===t.type&&"string"==typeof t.content)return[toInputText(t.content)];if("content"===t.type&&Array.isArray(t.content)){const e=[];for(const n of t.content){const t=blockToOpenAIContentBlocks(n);t&&e.push(...t)}return e.length>0?e:null}return null}if("search_result"===e.type&&Array.isArray(e.content)){const t=[];"string"==typeof e.title&&e.title.trim()&&t.push(e.title.trim()),"string"==typeof e.source&&e.source.trim()&&t.push(e.source.trim());for(const n of e.content)if(n&&"object"==typeof n&&"text"in n){const e=n.text;"string"==typeof e&&e.trim()&&t.push(e.trim())}return[toInputText(t.join("\n\n"))]}if("container_upload"===e.type&&"string"==typeof e.file_id)return[{type:"input_file",file_id:e.file_id}];if(("bash_code_execution_output"===e.type||"mcp_tool_result"===e.type||"code_execution_tool_result"===e.type||"web_search_tool_result"===e.type||"web_fetch_tool_result"===e.type||"text_editor_code_execution_tool_result"===e.type||"tool_search_tool_result"===e.type)&&"content"in e){const t=e.content;if("string"==typeof t)return[toInputText(t)];if(Array.isArray(t)){const e=[];for(const n of t){const t=blockToOpenAIContentBlocks(n);t&&e.push(...t)}return e.length>0?e:null}}if("content"in e&&("string"==typeof e.content||Array.isArray(e.content))){const t=e.content;if("string"==typeof t)return[toInputText(t)];const n=[];for(const e of t){const t=blockToOpenAIContentBlocks(e);t&&n.push(...t)}return n.length>0?n:null}return"data"in e&&"string"==typeof e.data?[toInputText(e.data)]:null}function toolResultContentToOpenAIOutput(e){if("string"==typeof e)return e;if(!Array.isArray(e))return stringifyBlockContent(e);const t=[];for(const n of e){const e=blockToOpenAIContentBlocks(n);if(e&&e.length>0){t.push(...e);continue}const o=stringifyBlockContent(n).trim();o&&t.push(toInputText(o))}return 0===t.length?"":t.every(e=>"input_text"===e.type)?t.map(e=>e.text).join("\n\n"):t}function messageToOpenAIInput(e){if(!e.message||"user"!==e.type&&"assistant"!==e.type)return[];const t=Array.isArray(e.message.content)?e.message.content:[{type:"text",text:String(e.message.content??"")}],n="assistant"===e.type?"assistant":"user",o=[],r=[],flushMessage=()=>{0!==r.length&&(o.push({type:"message",role:n,content:[...r]}),r.length=0)};for(const s of t){if("assistant"===e.type&&"tool_use"===s.type&&"string"==typeof s.id&&"string"==typeof s.name){flushMessage(),o.push({type:"function_call",call_id:s.id,name:s.name,arguments:O(s.input??{})});continue}if("user"===e.type&&"tool_result"===s.type&&"string"==typeof s.tool_use_id){flushMessage(),o.push({type:"function_call_output",call_id:s.tool_use_id,output:toolResultContentToOpenAIOutput(s.content)});continue}if("thinking"===s.type||"redacted_thinking"===s.type)continue;const t=blockToOpenAIContentBlocks(s);t&&t.length>0?r.push(...normalizeBlocksForRole(t,n)):r.push(..."assistant"===n?[toOutputText(stringifyBlockContent(s))]:[toInputText(stringifyBlockContent(s))])}return flushMessage(),o}async function readOpenAIResponseBody(e){const t=await e.text();if(!t.trim())return{};const n=t.trim();if(n.startsWith("data:")||n.startsWith("event:"))return function(e){const t=[];for(const n of e.split(/\r?\n\r?\n/)){const e=n.split(/\r?\n/).map(e=>e.trim()).filter(Boolean);if(0===e.length)continue;const o=e.filter(e=>e.startsWith("data:")).map(e=>e.slice(5).trim());if(0===o.length)continue;const r=o.join("\n").trim();if(r&&"[DONE]"!==r)try{const e=JSON.parse(r);isRecord(e)&&t.push(e)}catch{}}let n=null,o=null;const r=[];let s="";for(const i of t){const t="string"==typeof i.type?i.type:"";"response.completed"===t&&isRecord(i.response)?n={...i.response,raw_error_text:e}:"error"!==t?"response.output_item.done"===t&&isRecord(i.item)?r.push(i.item):"response.output_text.delta"!==t||"string"!=typeof i.delta?"response.output_text.done"===t&&"string"==typeof i.text&&(s=i.text):s+=i.delta:"string"==typeof i.message&&i.message.trim()?o=i.message:isRecord(i.error)&&"string"==typeof i.error.message&&(o=i.error.message)}if(n)return(!n.output||0===n.output.length)&&r.length>0&&(n.output=r),!n.output_text&&s&&(n.output_text=s),!n.error&&o&&(n.error={message:o}),n;if(r.length>0||s||o)return{output:r.length>0?r:void 0,output_text:s||void 0,error:o?{message:o}:void 0,raw_error_text:e};return{error:{message:e},raw_error_text:e}}(t);try{const e=JSON.parse(t);return isRecord(e)&&"string"==typeof e.error?{...e,error:{message:e.error},raw_error_text:t}:isRecord(e)?{...e,raw_error_text:t}:{error:{message:t},raw_error_text:t}}catch{return{error:{message:t},raw_error_text:t}}}function buildOpenAIErrorMessage(e){const t=e.data.error?.message?.trim()||e.data.raw_error_text?.trim()||`OpenAI request failed (${e.status} ${e.statusText})`,n=/requires a subscription|upgrade for access/i.test(t)?`El modelo ${e.model??"seleccionado"} requiere una suscripcion de Ollama Cloud. Cambia a otro modelo en /model o actualiza tu plan de Ollama.`:t,o=e.data.raw_error_text?.trim(),r=o&&o!==t&&o!==n?o.replace(/\s+/g," ").slice(0,400):null;return r?`${n} [model=${e.model??"unknown"} endpoint=${e.url}] ${r}`:`${n} [model=${e.model??"unknown"} endpoint=${e.url}]`}function blockToChatContentPart(e){if("text"===e.type&&"string"==typeof e.text)return{type:"text",text:e.text};if("image"===e.type){const t=isRecord(e.source)?e.source:null;if(!t)return null;if("base64"===t.type&&"string"==typeof t.data&&"string"==typeof t.media_type)return{type:"image_url",image_url:{url:`data:${t.media_type};base64,${t.data}`}};if("url"===t.type&&"string"==typeof t.url)return{type:"image_url",image_url:{url:t.url}}}const t=stringifyBlockContent(e);return t?{type:"text",text:t}:null}function toolResultToString(e){return"string"==typeof e?e:Array.isArray(e)?e.map(e=>"string"==typeof e?e:isRecord(e)&&"string"==typeof e.text?e.text:stringifyBlockContent(e)).filter(Boolean).join("\n"):stringifyBlockContent(e)}function messageToChatMessages(e){if(!e.message||"user"!==e.type&&"assistant"!==e.type)return[];const t=e.message.content,n=Array.isArray(t)?t:[{type:"text",text:String(t??"")}];if("assistant"===e.type){const e=[],t=[];for(const o of n)"thinking"!==o.type&&"redacted_thinking"!==o.type&&("tool_use"===o.type&&"string"==typeof o.id&&"string"==typeof o.name?e.push({id:o.id,type:"function",function:{name:o.name,arguments:O(o.input??{})}}):"text"===o.type&&"string"==typeof o.text&&o.text.trim()&&t.push(o.text));const o={role:"assistant",content:t.join("\n")};return e.length>0&&(o.tool_calls=e),[o]}const o=[],r=[];for(const e of n)if("tool_result"===e.type&&"string"==typeof e.tool_use_id)o.push({role:"tool",tool_call_id:e.tool_use_id,content:toolResultToString(e.content)});else{const t=blockToChatContentPart(e);t&&r.push(t)}const s=[...o];if(r.length>0){const e=r.every(e=>"text"===e.type);s.push({role:"user",content:e?r.map(e=>e.text).join("\n"):r})}return s}function parseChatCompletionResponse(e){const t=[];for(const n of e.choices??[]){const e=n.message;if(e){"string"==typeof e.content&&e.content.trim()&&t.push({type:"text",text:e.content});for(const n of e.tool_calls??[])t.push({type:"tool_use",id:n.id,name:n.function?.name??"tool",input:parseFunctionCallArguments(n.function?.arguments)})}}return{content:t}}function getChatUsage(e){if("number"==typeof e.usage?.prompt_tokens||"number"==typeof e.usage?.completion_tokens)return{input_tokens:e.usage?.prompt_tokens??0,output_tokens:e.usage?.completion_tokens??0}}function buildChatToolChoice(e){if(!e.toolChoice)return"auto";switch(e.toolChoice.type){case"auto":default:return"auto";case"any":return"required";case"none":return"none";case"tool":return"string"==typeof e.toolChoice.name?{type:"function",function:{name:e.toolChoice.name}}:"auto"}}function chatContentToGeminiParts(e){return"string"==typeof e?e?[{text:e}]:[]:Array.isArray(e)?e.map(e=>"text"===e.type?e.text?{text:e.text}:null:"image_url"===e.type?{text:`[Image input: ${e.image_url.url}]`}:null).filter(e=>null!==e):[]}function buildGeminiContents(e){const t=new Map,n=[];for(const o of e){if("system"===o.role)continue;if("assistant"===o.role){const e=chatContentToGeminiParts(o.content);for(const n of o.tool_calls??[]){t.set(n.id,n.function.name);const o=parseFunctionCallArguments(n.function.arguments);e.push({functionCall:{name:n.function.name,args:isPlainObject(o)?o:{raw:o}}})}e.length>0&&n.push({role:"model",parts:e});continue}if("tool"===o.role){const e=o.tool_call_id?t.get(o.tool_call_id)??"tool":"tool";n.push({role:"function",parts:[{functionResponse:{name:e,response:{result:o.content??""}}}]});continue}const e=chatContentToGeminiParts(o.content);e.length>0&&n.push({role:"user",parts:e})}return n.length>0?n:[{role:"user",parts:[{text:""}]}]}function getGeminiEnumType(e){switch(typeof e){case"string":return"string";case"number":return Number.isInteger(e)?"integer":"number";case"boolean":return"boolean";default:return}}function sanitizeGeminiSchema(e){if(!isRecord(e))return{type:"object",properties:{}};const t=Array.isArray(e.anyOf)?e.anyOf:Array.isArray(e.any_of)?e.any_of:null,n=Array.isArray(e.oneOf)?e.oneOf:Array.isArray(e.one_of)?e.one_of:null;if(t||n){const e=function(e){const t=[];let n,o=!1;for(const r of e){if(!isRecord(r))return null;if("null"===r.type){o=!0;continue}const e=void 0!==r.const?[r.const]:Array.isArray(r.enum)?r.enum:null;if(!e)return null;for(const o of e){const e=getGeminiEnumType(o);if(!e)return null;if(n&&n!==e)return null;n=e,t.push(o)}}return n&&0!==t.length?{type:n,enum:Array.from(new Set(t)),...o?{nullable:!0}:{}}:null}(t??n??[]);return e||{anyOf:(t??n??[]).map(sanitizeGeminiSchema)}}const o={},r=e.type;if(Array.isArray(r)){const e=r.find(e=>"null"!==e);"string"==typeof e&&(o.type=e),r.includes("null")&&(o.nullable=!0)}else"string"==typeof r&&(o.type=r);for(const t of["title","description","format","nullable","minimum","maximum","minItems","maxItems","minLength","maxLength","pattern"])void 0!==e[t]&&(o[t]=e[t]);if(Array.isArray(e.enum)?o.enum=e.enum:void 0!==e.const&&(o.enum=[e.const]),!o.type&&Array.isArray(o.enum)&&o.enum.length>0&&(o.type=getGeminiEnumType(o.enum[0])),void 0!==e.exclusiveMinimum&&void 0===o.minimum&&(o.minimum="number"==typeof e.exclusiveMinimum?e.exclusiveMinimum:e.minimum),void 0!==e.exclusiveMaximum&&void 0===o.maximum&&(o.maximum="number"==typeof e.exclusiveMaximum?e.exclusiveMaximum:e.maximum),isRecord(e.items)?o.items=sanitizeGeminiSchema(e.items):Array.isArray(e.items)&&e.items.length>0&&(o.items=sanitizeGeminiSchema(e.items[0])),isRecord(e.properties)){const t={};for(const[n,o]of Object.entries(e.properties))t[n]=sanitizeGeminiSchema(o);o.properties=t}return Array.isArray(e.required)&&(o.required=e.required.filter(e=>"string"==typeof e)),o.type||(o.type=o.properties?"object":o.items?"array":"object"),"object"!==o.type||o.properties||(o.properties={}),o}async function postGeminiCodeAssist(e,t,n,o){const r=await fetch(`https://cloudcode-pa.googleapis.com/v1internal:${e}`,{method:"POST",headers:t,body:O(n),signal:o});return{response:r,data:await readOpenAIResponseBody(r)}}function getGeminiCodeAssistMetadata(e){return{ideType:"IDE_UNSPECIFIED",platform:"PLATFORM_UNSPECIFIED",pluginType:"GEMINI",...e?{duetProject:e}:{}}}async function resolveGeminiCodeAssistProject(e,t){const n=process.env.GEMINI_GOOGLE_PROJECT_ID?.trim()||void 0,o={...n?{cloudaicompanionProject:n}:{},metadata:getGeminiCodeAssistMetadata(n)},{response:r,data:s}=await postGeminiCodeAssist("loadCodeAssist",e,o,t);if(!r.ok)return n;if("string"==typeof s.cloudaicompanionProject)return s.cloudaicompanionProject;if(n)return n;const i=Array.isArray(s.allowedTiers)?s.allowedTiers.filter(isRecord):[],a=i.find(e=>!0===e.isDefault)??i[0],u="string"==typeof a?.id?a.id:void 0;if(!u)return;const{response:l,data:c}=await postGeminiCodeAssist("onboardUser",e,{tierId:u,metadata:getGeminiCodeAssistMetadata()},t);if(!l.ok)return;const p=isRecord(c.response)?c.response:c,m=isRecord(p.cloudaicompanionProject)?p.cloudaicompanionProject:null;return"string"==typeof m?.id?m.id:void 0}async function createGeminiGoogleChatCompletionResponse(e){const{model:n,chatMessages:r,chatTools:s,toolChoice:i,signal:a,maxOutputTokens:u,temperature:l}=e,c=await o(),p=await resolveGeminiCodeAssistProject(c,a),d={};u&&(d.maxOutputTokens=u),void 0!==l&&(d.temperature=l);const f={contents:buildGeminiContents(r),session_id:t()},g=r.filter(e=>"system"===e.role&&"string"==typeof e.content).map(e=>e.content).join("\n\n");g&&(f.systemInstruction={role:"user",parts:[{text:g}]});const y=function(e){if(0!==e.length)return[{functionDeclarations:e.map(e=>({name:e.function.name,description:e.function.description,parameters:sanitizeGeminiSchema(e.function.parameters??{type:"object",properties:{}})}))}]}(s);y&&(f.tools=y);const h=function(e){if("auto"!==e)return"none"===e?{functionCallingConfig:{mode:"NONE"}}:"required"===e?{functionCallingConfig:{mode:"ANY"}}:{functionCallingConfig:{mode:"ANY",allowedFunctionNames:[e.function.name]}}}(i);h&&(f.toolConfig=h),Object.keys(d).length>0&&(f.generationConfig=d);let _=n;const A=n.toLowerCase();_=A.includes("flash")?"gemini-3-flash-preview":(A.includes("pro"),"gemini-3.1-pro-preview");const C={model:_,...p?{project:p}:{},user_prompt_id:t(),request:f},b="https://cloudcode-pa.googleapis.com/v1internal:generateContent";m(`[Gemini Google] codeassist generateContent request model=${_} (original=${n}) messages=${r.length} tools=${s.length} endpoint=${b}`);const{response:x,data:I}=await postGeminiCodeAssist("generateContent",c,C,a);if(!x.ok)throw m(`[Gemini Google] codeassist generateContent error status=${x.status} model=${n} endpoint=${b} body=${(I.error?.message??"").replace(/\s+/g," ").slice(0,500)}`,{level:"error"}),new Error(buildOpenAIErrorMessage({status:x.status,statusText:x.statusText,url:b,model:n,data:I}));return function(e){const n=e.response?.candidates??[];return{id:e.traceId,choices:n.map(e=>{const n=[],o=[];for(const r of e.content?.parts??[])"text"in r&&"string"==typeof r.text&&n.push(r.text),"functionCall"in r&&r.functionCall?.name&&o.push({id:`call_${t().replace(/-/g,"")}`,type:"function",function:{name:r.functionCall.name,arguments:O(r.functionCall.args??{})}});return{message:{content:n.join("")||null,tool_calls:o.length>0?o:void 0},finish_reason:e.finishReason}}),usage:{prompt_tokens:e.response?.usageMetadata?.promptTokenCount,completion_tokens:e.response?.usageMetadata?.candidatesTokenCount}}}(I)}async function createChatCompletionResponse({messages:e,systemPrompt:t,tools:n,signal:o,options:s}){const i=getOpenAICompatibleProvider();await maybeRefreshOpenAICompatibleAuth(i);const a=t.join("\n\n"),u=[...a?[{role:"system",content:a}]:[],...e.flatMap(messageToChatMessages)],l=function(e){return e.map(e=>({type:"function",function:{name:e.name,description:e.description,parameters:e.parameters,...e.strict?{strict:!0}:{}}}))}(await buildOpenAITools(n,s)),c={model:s.model,messages:u,stream:"custom-openai"!==i,..."custom-openai"!==i?{stream_options:{include_usage:!0}}:{}};if(l.length>0&&(c.tools=l,c.tool_choice=buildChatToolChoice(s)),shouldDisableParallelToolCalls(s)&&(c.parallel_tool_calls=!1),s.maxOutputTokensOverride&&(c.max_tokens=s.maxOutputTokensOverride),void 0!==s.temperatureOverride&&(c.temperature=s.temperatureOverride),s.effortValue&&(c.reasoning_effort=s.effortValue),"gemini-google"===i)return createGeminiGoogleChatCompletionResponse({model:String(s.model),chatMessages:u,chatTools:l,toolChoice:buildChatToolChoice(s),signal:o,maxOutputTokens:s.maxOutputTokensOverride,temperature:s.temperatureOverride});const p=getOpenAIMaxTimeoutRetries(),sendRequest=async(e=r(i)??"",t=0)=>{const n=`${getOpenAIBaseUrl(i)}/chat/completions`;m(`[${getOpenAICompatibleProviderLabel(i)}] chat.completions request model=${s.model} messages=${u.length} tools=${l.length} endpoint=${n}${t>0?` (retry ${t})`:""}`);const a=12e4,d=new AbortController,f=setTimeout(()=>d.abort(),a),onAbort=()=>d.abort();o?.addEventListener("abort",onAbort);try{if("custom-openai"===i)try{const e=require("fs"),t=`--- NUEVA SOLICITUD A CHINAI ---\nFecha: ${(new Date).toISOString()}\nURL: ${n}\nHeaders: ${JSON.stringify(await getOpenAIRequestHeaders(i),null,2)}\nBody: ${JSON.stringify(c,null,2)}\n\n`;e.writeFileSync("d:/Documents/GitHub/Claude/claude-code_V1/Context_Code_V1/chat-debug.txt",t)}catch(e){}m(`[${getOpenAICompatibleProviderLabel(i)}] chat.completions REQUEST BODY: ${O(c).slice(0,3e3)}`);const o=await fetch(n,{method:"POST",headers:await getOpenAIRequestHeaders(i),body:O(c),signal:d.signal}),r=await o.text();if("custom-openai"===i)try{const e=require("fs"),t=`--- RESPUESTA DE CHINAI ---\nStatus: ${o.status} ${o.statusText}\nBody: ${r}\n\n`;e.appendFileSync("d:/Documents/GitHub/Claude/claude-code_V1/Context_Code_V1/chat-debug.txt",t)}catch(e){}let a;m(`[${getOpenAICompatibleProviderLabel(i)}] chat.completions RAW response status=${o.status} bodyLength=${r.length} bodyPreview=${r.slice(0,3e3)}`);const u=r.trim();if(u.startsWith("data:")||u.startsWith("event:")){const e=function(e){const t=[];for(const n of e.split(/\r?\n\r?\n/)){const e=n.split(/\r?\n/).map(e=>e.trim()).filter(e=>e.startsWith("data:")).map(e=>e.slice(5).trim());if(0===e.length)continue;const o=e.join("\n").trim();if(o&&"[DONE]"!==o)try{const e=JSON.parse(o);isRecord(e)&&t.push(e)}catch{}}if(0===t.length)return null;if(!t.some(e=>{const t=e.object;return"string"==typeof t&&t.startsWith("chat.completion")}))return null;let n,o,r,s,i="",a="";const u=new Map;for(const e of t){if(n||"string"!=typeof e.id||(n=e.id),isRecord(e.usage)){const t=e.usage;"number"==typeof t.prompt_tokens&&(r=t.prompt_tokens),"number"==typeof t.completion_tokens&&(s=t.completion_tokens)}const t=Array.isArray(e.choices)?e.choices:[];for(const e of t){if(!isRecord(e))continue;"string"==typeof e.finish_reason&&(o=e.finish_reason);const t=isRecord(e.delta)?e.delta:null,n=isRecord(e.message)?e.message:null,r=t??n;if(!r)continue;"string"==typeof r.content&&(i+=r.content),"string"==typeof r.reasoning_content&&(a+=r.reasoning_content);const s=Array.isArray(r.tool_calls)?r.tool_calls:[];for(const e of s){if(!isRecord(e))continue;const t="number"==typeof e.index?e.index:0,n=u.get(t)??{arguments:""};"string"==typeof e.id&&(n.id=e.id);const o=isRecord(e.function)?e.function:null;o&&("string"==typeof o.name&&(n.name=o.name),"string"==typeof o.arguments&&(n.arguments+=o.arguments)),u.set(t,n)}}}const l=i||(a?a.trim():""),c=[];for(const[,e]of[...u.entries()].sort((e,t)=>e[0]-t[0]))e.name&&c.push({id:e.id??`call_${c.length}`,type:"function",function:{name:e.name,arguments:e.arguments}});return{id:n,choices:[{message:{content:l||null,...c.length>0?{tool_calls:c}:{}},finish_reason:o}],usage:{prompt_tokens:r,completion_tokens:s}}}(r);if(e)a=e;else try{a=JSON.parse(r)}catch{a={error:{message:r.slice(0,500)}}}}else if(u)try{a=JSON.parse(r)}catch{a={error:{message:r.slice(0,500)}}}else a={};if(504===o.status&&t<1)return m(`[${getOpenAICompatibleProviderLabel(i)}] 504 Gateway Timeout, reintentando...`,{level:"warn"}),sendRequest(e,t+1);if(401===o.status){const n=await maybeRecoverOpenAICompatible401(e,i);if(n)return sendRequest(n,t)}if(!o.ok)throw m(`[${getOpenAICompatibleProviderLabel(i)}] chat.completions error status=${o.status} model=${s.model} endpoint=${n} body=${(a.error?.message??"").replace(/\s+/g," ").slice(0,500)}`,{level:"error"}),new Error(buildOpenAIErrorMessage({status:o.status,statusText:o.statusText,url:n,model:String(s.model),data:a}));return a}catch(n){if(n instanceof Error&&"AbortError"===n.name&&!o?.aborted){if(t<p){const n=1e3*Math.pow(2,t);return m(`[${getOpenAICompatibleProviderLabel(i)}] timeout local tras 120000ms, reintentando en ${n}ms (intento ${t+1}/${p})`,{level:"warn"}),await new Promise(e=>setTimeout(e,n)),sendRequest(e,t+1)}throw new Error("La solicitud expiró tras 120s. El servidor tardó demasiado en responder.")}throw n}finally{clearTimeout(f),o?.removeEventListener("abort",onAbort)}};return getOpenAIAccessTokenOrThrow(i),sendRequest()}async function buildOpenAITools(e,t){return(await Promise.all(e.map(n=>A(n,{getToolPermissionContext:t.getToolPermissionContext,tools:e,agents:t.agents,allowedAgentTypes:t.allowedAgentTypes,model:t.model})))).map(e=>({type:"function",name:e.name,description:e.description,parameters:e.input_schema,...e.strict?{strict:!0}:{}}))}function buildToolChoice(e){if(!e.toolChoice)return"auto";switch(e.toolChoice.type){case"auto":default:return"auto";case"any":return"required";case"none":return"none";case"tool":return"string"==typeof e.toolChoice.name?{type:"function",name:e.toolChoice.name}:"auto"}}function shouldDisableParallelToolCalls(e){const t=e.toolChoice;return Boolean(t&&"disable_parallel_tool_use"in t&&!0===t.disable_parallel_tool_use)}function parseFunctionCallArguments(e){if(isPlainObject(e))return e;if("string"!=typeof e)return null==e?{}:{raw:e};try{const t=JSON.parse(e);return isPlainObject(t)?t:{raw:t}}catch{return{raw:e}}}function parseOutputItems(e){const t=[];for(const n of e.output??[])if(n&&"object"==typeof n){if("function_call"===n.type){const e=parseFunctionCallArguments(n.arguments);t.push({type:"tool_use",id:String(n.call_id??n.id??""),name:String(n.name??"tool"),input:e});continue}if("message"===n.type)for(const e of normalizeResponseContent(n.content)){if("string"==typeof e){t.push({type:"text",text:e});continue}if(!e||"object"!=typeof e||!("type"in e))continue;const n=String(e.type??""),o="string"==typeof e.text?e.text??"":"string"==typeof e.refusal?e.refusal??"":"";"output_text"!==n&&"text"!==n&&"refusal"!==n||!o||t.push({type:"text",text:o})}}return 0===t.length&&"string"==typeof e.output_text&&t.push({type:"text",text:e.output_text}),{content:t}}function getUsage(e){if("number"==typeof e.usage?.input_tokens||"number"==typeof e.usage?.output_tokens)return{input_tokens:e.usage?.input_tokens??0,output_tokens:e.usage?.output_tokens??0}}function sideQueryMessageToOpenAIInput(e){const t=Array.isArray(e.content)?e.content.filter(e=>"text"===e?.type&&"string"==typeof e.text).map(e=>toInputText(e.text)):[toInputText(String(e.content??""))];return[{type:"message",role:e.role,content:t.length>0?t:[toInputText("")]}]}function sideQueryToolToOpenAITool(e){return{type:"function",name:e.name,description:e.description,parameters:e.input_schema??{type:"object",properties:{}}}}function buildSideQueryToolChoice(e){return e&&"auto"!==e?"none"===e||"none"===e.type?"none":"any"===e.type?"required":"auto"===e.type?"auto":"string"==typeof e.name&&e.name?{type:"function",name:e.name}:"auto":"auto"}function sideQueryMessageToChatMessage(e){const t=Array.isArray(e.content)?e.content.filter(e=>"text"===e?.type&&"string"==typeof e.text).map(e=>e.text).join("\n"):String(e.content??"");return{role:e.role,content:t}}function sideQueryToolToChatTool(e){return{type:"function",function:{name:e.name,description:e.description,parameters:e.input_schema??{type:"object",properties:{}}}}}export async function queryOpenAISideQuery({model:e,systemPrompt:t,messages:n,tools:o,toolChoice:s,outputFormat:i,signal:a,maxOutputTokens:u,temperature:l}){const c=getOpenAICompatibleProvider();await maybeRefreshOpenAICompatibleAuth(c);const p=getOpenAIBaseUrl(c),d=r(c);if(!("openai"===c&&d&&isJwtToken(d))){const r=[...t?[{role:"system",content:t}]:[],...n.map(sideQueryMessageToChatMessage)],d={model:e,messages:r,stream:!1},f=o?.map(sideQueryToolToChatTool)??[],g=function(e){const t=buildSideQueryToolChoice(e);return"auto"===t||"none"===t?t:"required"===t?"required":{type:"function",function:{name:t.name}}}(s);if(f.length>0&&(d.tools=f,d.tool_choice=g),"json_schema"===i?.type&&(d.response_format={type:"json_schema",json_schema:{name:"side_query_output",strict:!0,schema:i.schema}}),u&&(d.max_tokens=u),void 0!==l&&(d.temperature=l),"gemini-google"===c){const t=await createGeminiGoogleChatCompletionResponse({model:e,chatMessages:r,chatTools:f,toolChoice:g,signal:a,maxOutputTokens:u,temperature:l});return{id:t.id,content:parseChatCompletionResponse(t).content,usage:getChatUsage(t)}}const y=`${p}/chat/completions`,h=await getOpenAIRequestHeaders(c);if("custom-openai"===c)try{const e=require("fs"),t=`--- NUEVA SOLICITUD DE VALIDACION DE MODELO A CHINAI ---\nFecha: ${(new Date).toISOString()}\nURL: ${y}\nHeaders: ${JSON.stringify(h,null,2)}\nBody: ${JSON.stringify(d,null,2)}\n\n`;e.appendFileSync("d:/Documents/GitHub/Claude/claude-code_V1/Context_Code_V1/chat-debug.txt",t)}catch(e){}const _=await fetch(y,{method:"POST",headers:h,body:O(d),signal:a});if("custom-openai"===c)try{const e=_.clone(),t=await e.text(),n=require("fs"),o=`--- RESPUESTA DE VALIDACION DE MODELO DE CHINAI ---\nStatus: ${_.status} ${_.statusText}\nBody: ${t}\n\n`;n.appendFileSync("d:/Documents/GitHub/Claude/claude-code_V1/Context_Code_V1/chat-debug.txt",o)}catch(e){}const A=await readOpenAIResponseBody(_);if(!_.ok)throw m(`[${getOpenAICompatibleProviderLabel(c)}] sideQuery chat.completions error status=${_.status} model=${e} endpoint=${y} body=${(A.error?.message??"").replace(/\s+/g," ").slice(0,500)}`,{level:"error"}),new Error(buildOpenAIErrorMessage({status:_.status,statusText:_.statusText,url:y,model:e,data:A}));return{id:A.id,content:parseChatCompletionResponse(A).content,usage:getChatUsage(A)}}const f={model:e,input:n.flatMap(sideQueryMessageToOpenAIInput),instructions:t,stream:!1,store:!1};o&&o.length>0&&(f.tools=o.map(sideQueryToolToOpenAITool),f.tool_choice=buildSideQueryToolChoice(s)),"json_schema"===i?.type&&(f.text={format:{type:"json_schema",name:"side_query_output",strict:!0,schema:i.schema}}),u&&(f.max_output_tokens=u),void 0!==l&&(f.temperature=l);const g=`${p}/responses`,y=await fetch(g,{method:"POST",headers:await getOpenAIRequestHeaders(c),body:O(f),signal:a}),h=await readOpenAIResponseBody(y);if(!y.ok)throw m(`[${getOpenAICompatibleProviderLabel(c)}] sideQuery error status=${y.status} model=${e} endpoint=${p}/responses body=${(h.raw_error_text??"").replace(/\s+/g," ").slice(0,500)}`,{level:"error"}),new Error(buildOpenAIErrorMessage({status:y.status,statusText:y.statusText,url:`${p}/responses`,model:e,data:h}));return{id:h.id,content:parseOutputItems(h).content,usage:getUsage(h)}}async function createOpenAIResponse(e){const{messages:t,systemPrompt:n,tools:o,signal:r,options:s}=e,i=getOpenAICompatibleProvider();await maybeRefreshOpenAICompatibleAuth(i);const a=getOpenAIAccessTokenOrThrow(i),u="openai"===i&&isJwtToken(a);if(!u){const t=await createChatCompletionResponse(e);return{id:t.id,output:t.choices?.flatMap(e=>{const t=[];if(e.message?.content&&t.push({type:"message",role:"assistant",content:[e.message.content]}),e.message?.tool_calls)for(const n of e.message.tool_calls)t.push({type:"function_call",call_id:n.id,name:n.function.name,arguments:n.function.arguments});return t})??[],usage:{input_tokens:t.usage?.prompt_tokens,output_tokens:t.usage?.completion_tokens}}}const l=t.flatMap(messageToOpenAIInput),p=await buildOpenAITools(o,s),d={model:s.model,input:l,instructions:n.join("\n\n"),tools:p,tool_choice:buildToolChoice(s),stream:!1,store:!1};shouldDisableParallelToolCalls(s)&&(d.parallel_tool_calls=!1),s.maxOutputTokensOverride&&(d.max_output_tokens=s.maxOutputTokensOverride),void 0!==s.temperatureOverride&&(d.temperature=s.temperatureOverride),s.effortValue&&(d.reasoning={effort:s.effortValue});const f=getOpenAIMaxTimeoutRetries(),sendRequest=async(e,t=0)=>{const n=u?{...d,stream:!0}:d;let o,a;if(u){const t=function(e){try{const t=JSON.parse(atob(e.split(".")[1])),n=t?.["https://api.openai.com/auth"]?.chatgpt_account_id;if(!n)throw new Error("No account ID in token");return n}catch{throw new Error("Failed to extract chatgpt-account-id from OAuth token")}}(e);o=function(){const e=(process.env.OPENAI_OAUTH_BASE_URL||"https://chatgpt.com/backend-api").replace(/\/+$/,"");return e.endsWith("/codex/responses")?e:e.endsWith("/codex")?`${e}/responses`:`${e}/codex/responses`}(),a={Authorization:`Bearer ${e}`,"chatgpt-account-id":t,"OpenAI-Beta":"responses=experimental",originator:c(),"content-type":"application/json",accept:"application/json"}}else o=`${getOpenAIBaseUrl(i)}/responses`,a={Authorization:`Bearer ${e}`,"Content-Type":"application/json"};const l=12e4,p=new AbortController,g=setTimeout(()=>p.abort(),l),onAbort=()=>p.abort();r?.addEventListener("abort",onAbort);try{const r=await fetch(o,{method:"POST",headers:a,body:O(n),signal:p.signal}),l=await readOpenAIResponseBody(r);if(504===r.status&&t<1)return m(`[${getOpenAICompatibleProviderLabel(i)}] responses 504 Gateway Timeout, reintentando...`,{level:"warn"}),sendRequest(e,t+1);if(401===r.status){const n=await maybeRecoverOpenAICompatible401(e,i);if(n)return sendRequest(n,t)}if(!r.ok)throw m(`[${getOpenAICompatibleProviderLabel(i)}] responses error status=${r.status} model=${s.model} endpoint=${o} oauth=${u} body=${(l.raw_error_text??"").replace(/\s+/g," ").slice(0,500)}`,{level:"error"}),new Error(buildOpenAIErrorMessage({status:r.status,statusText:r.statusText,url:o,model:String(s.model),data:l}));return l}catch(n){if(n instanceof Error&&"AbortError"===n.name&&!r?.aborted){if(t<f){const n=1e3*Math.pow(2,t);return m(`[${getOpenAICompatibleProviderLabel(i)}] responses timeout local tras 120000ms, reintentando en ${n}ms (intento ${t+1}/${f})`,{level:"warn"}),await new Promise(e=>setTimeout(e,n)),sendRequest(e,t+1)}throw new Error("La solicitud expiró tras 120s. El servidor tardó demasiado en responder.")}throw n}finally{clearTimeout(g),r?.removeEventListener("abort",onAbort)}};return sendRequest(a)}export async function*queryOpenAIModelWithStreaming({messages:t,systemPrompt:n,thinkingConfig:o,tools:r,signal:s,options:i}){try{for(let e=1;e<=2;e++){const o=await createOpenAIResponse({messages:1===e?t:[...t,y({content:"System reminder: your previous response for this turn was empty. Continue the current task without asking the user to repeat themselves. If a tool call is needed, emit the appropriate tool call now. Do not return an empty response.",isMeta:!0})],systemPrompt:n,tools:r,signal:s,options:i}),{content:a}=parseOutputItems(o),u=getUsage(o);if(u)try{const e={input_tokens:u.input_tokens??0,output_tokens:u.output_tokens??0,cache_read_input_tokens:0,cache_creation_input_tokens:0},t=String(i.model),n=_(t,e);h(n,e,t)}catch(e){d(e)}if(a.length>0)return void(yield g({content:a,usage:u}));if(!(e<2))return void(yield f({content:"OpenAI returned no content after retrying."}));m(`[${getOpenAICompatibleProviderLabel(getOpenAICompatibleProvider())}] empty model response with no content; retrying request (${e}/1)`,{level:"warn"})}}catch(t){if(s.aborted)throw new e;d(t),yield f({content:p(t),errorDetails:p(t)})}}
@@ -1 +1 @@
1
- import{createServer as e}from"http";import{logEvent as t}from"../analytics/index.js";import{getOauthConfig as r,getOpenAIOAuthConfig as o}from"../../constants/oauth.js";import{logError as i}from"../../utils/log.js";import{shouldUseClaudeAIAuth as s}from"./client.js";export class AuthCodeListener{static activeByPort=new Map;localServer;port=0;promiseResolver=null;promiseRejecter=null;expectedState=null;pendingResponse=null;callbackPath;constructor(t="/callback"){this.localServer=e(),this.callbackPath=t}async start(e,t="localhost"){const r=e??0;if(r>0&&AuthCodeListener.activeByPort.has(r)){AuthCodeListener.activeByPort.get(r).close(),AuthCodeListener.activeByPort.delete(r),await new Promise(e=>setTimeout(e,150))}return new Promise((e,o)=>{this.localServer.once("error",e=>{"EADDRINUSE"===e.code&&r>0?o(new Error(`El puerto ${r} sigue ocupado. Cierra cualquier otro proceso de login y vuelve a intentarlo.`)):o(new Error(`Failed to start OAuth callback server: ${e.message}`))}),this.localServer.listen(r,t,()=>{const t=this.localServer.address();this.port=t.port,r>0&&AuthCodeListener.activeByPort.set(r,this),e(this.port)})})}getPort(){return this.port}hasPendingResponse(){return null!==this.pendingResponse}async waitForAuthorization(e,t){return new Promise((r,o)=>{this.promiseResolver=r,this.promiseRejecter=o,this.expectedState=e,this.startLocalListener(t)})}handleSuccessRedirect(e,i="anthropic",n){if(!this.pendingResponse)return;if(n)return n(this.pendingResponse,e),this.pendingResponse=null,void t("tengu_oauth_automatic_redirect",{custom_handler:!0});const a="openai"===i?o()?.SUCCESS_URL:s(e)?r().CLAUDEAI_SUCCESS_URL:r().CONSOLE_SUCCESS_URL;a?(this.pendingResponse.writeHead(302,{Location:a}),this.pendingResponse.end()):(this.pendingResponse.writeHead(200,{"Content-Type":"text/plain; charset=utf-8"}),this.pendingResponse.end("Login complete. You can return to the terminal.")),this.pendingResponse=null,t("tengu_oauth_automatic_redirect",{})}handleErrorRedirect(e="anthropic"){if(!this.pendingResponse)return;const i="openai"===e?o()?.SUCCESS_URL:r().CLAUDEAI_SUCCESS_URL;i?(this.pendingResponse.writeHead(302,{Location:i}),this.pendingResponse.end()):(this.pendingResponse.writeHead(200,{"Content-Type":"text/plain; charset=utf-8"}),this.pendingResponse.end("OAuth completed with an error. You can return to the terminal.")),this.pendingResponse=null,t("tengu_oauth_automatic_redirect_error",{})}startLocalListener(e){this.localServer.on("request",this.handleRedirect.bind(this)),this.localServer.on("error",this.handleError.bind(this)),e()}handleRedirect(e,t){const r=new URL(e.url||"",`http://${e.headers.host||"localhost"}`);if(r.pathname!==this.callbackPath)return t.writeHead(404),void t.end();const o=r.searchParams.get("code")??void 0,i=r.searchParams.get("state")??void 0,s=r.searchParams.get("error")??void 0,n=r.searchParams.get("error_description")??void 0,a=r.searchParams.get("error_uri")??void 0;this.validateAndRespond(o,i,t,{error:s,errorDescription:n,errorUri:a})}validateAndRespond(e,t,r,o){if(o?.error){r.writeHead(400,{"Content-Type":"text/plain; charset=utf-8"}),r.end(o.errorDescription??o.error);const e=[`OAuth provider error: ${o.error}`,o.errorDescription,o.errorUri].filter(Boolean).join("\n");return void this.reject(new Error(e))}return e?t!==this.expectedState?(r.writeHead(400),r.end("Invalid state parameter"),void this.reject(new Error("Invalid state parameter"))):(this.pendingResponse=r,void this.resolve(e)):(r.writeHead(400),r.end("Authorization code not found"),void this.reject(new Error("No authorization code received")))}handleError(e){i(e),this.close(),this.reject(e)}resolve(e){this.promiseResolver&&(this.promiseResolver(e),this.promiseResolver=null,this.promiseRejecter=null)}reject(e){this.promiseRejecter&&(this.promiseRejecter(e),this.promiseResolver=null,this.promiseRejecter=null)}close(){this.port>0&&AuthCodeListener.activeByPort.delete(this.port),this.pendingResponse&&this.handleErrorRedirect(),this.localServer&&(this.localServer.removeAllListeners(),"function"==typeof this.localServer.closeAllConnections&&this.localServer.closeAllConnections(),this.localServer.close())}}
1
+ import{createServer as e}from"http";import{logEvent as t}from"../analytics/index.js";import{getOauthConfig as r,getOpenAIOAuthConfig as o}from"../../constants/oauth.js";import{logError as s}from"../../utils/log.js";import{shouldUseClaudeAIAuth as i}from"./client.js";export class AuthCodeListener{static activeByPort=new Map;localServer;port=0;promiseResolver=null;promiseRejecter=null;expectedState=null;pendingResponse=null;callbackPath;constructor(t="/callback"){this.localServer=e(),this.callbackPath=t}async start(e,t="localhost"){const r=e??0;if(r>0&&AuthCodeListener.activeByPort.has(r)){AuthCodeListener.activeByPort.get(r).close(),AuthCodeListener.activeByPort.delete(r),await new Promise(e=>setTimeout(e,150))}const tryListen=e=>new Promise((t,o)=>{const errorHandler=s=>{this.localServer.off("error",errorHandler),"EADDRINUSE"===s.code&&r>0?o(new Error(`El puerto ${r} sigue ocupado. Cierra cualquier otro proceso de login y vuelve a intentarlo.`)):"::"!==e&&"::1"!==e||"EADDRINUSE"===s.code?o(new Error(`Failed to start OAuth callback server on ${e}: ${s.message}`)):t(tryListen("127.0.0.1"))};this.localServer.once("error",errorHandler),this.localServer.listen(r,e,()=>{this.localServer.off("error",errorHandler);const e=this.localServer.address();this.port=e.port,r>0&&AuthCodeListener.activeByPort.set(r,this),t(this.port)})}),o="localhost"===t?"win32"===process.platform?"127.0.0.1":"::":t;return tryListen(o)}getPort(){return this.port}hasPendingResponse(){return null!==this.pendingResponse}async waitForAuthorization(e,t){return new Promise((r,o)=>{this.promiseResolver=r,this.promiseRejecter=o,this.expectedState=e,this.startLocalListener(t)})}handleSuccessRedirect(e,s="anthropic",n){if(!this.pendingResponse)return;if(n)return n(this.pendingResponse,e),this.pendingResponse=null,void t("tengu_oauth_automatic_redirect",{custom_handler:!0});const a="openai"===s?o()?.SUCCESS_URL:i(e)?r().CLAUDEAI_SUCCESS_URL:r().CONSOLE_SUCCESS_URL;a?(this.pendingResponse.writeHead(302,{Location:a}),this.pendingResponse.end()):(this.pendingResponse.writeHead(200,{"Content-Type":"text/plain; charset=utf-8"}),this.pendingResponse.end("Login complete. You can return to the terminal.")),this.pendingResponse=null,t("tengu_oauth_automatic_redirect",{})}handleErrorRedirect(e="anthropic"){if(!this.pendingResponse)return;const s="openai"===e?o()?.SUCCESS_URL:r().CLAUDEAI_SUCCESS_URL;s?(this.pendingResponse.writeHead(302,{Location:s}),this.pendingResponse.end()):(this.pendingResponse.writeHead(200,{"Content-Type":"text/plain; charset=utf-8"}),this.pendingResponse.end("OAuth completed with an error. You can return to the terminal.")),this.pendingResponse=null,t("tengu_oauth_automatic_redirect_error",{})}startLocalListener(e){this.localServer.on("request",this.handleRedirect.bind(this)),this.localServer.on("error",this.handleError.bind(this)),e()}handleRedirect(e,t){const r=new URL(e.url||"",`http://${e.headers.host||"localhost"}`);if(r.pathname!==this.callbackPath)return t.writeHead(404),void t.end();const o=r.searchParams.get("code")??void 0,s=r.searchParams.get("state")??void 0,i=r.searchParams.get("error")??void 0,n=r.searchParams.get("error_description")??void 0,a=r.searchParams.get("error_uri")??void 0;this.validateAndRespond(o,s,t,{error:i,errorDescription:n,errorUri:a})}validateAndRespond(e,t,r,o){if(o?.error){r.writeHead(400,{"Content-Type":"text/plain; charset=utf-8"}),r.end(o.errorDescription??o.error);const e=[`OAuth provider error: ${o.error}`,o.errorDescription,o.errorUri].filter(Boolean).join("\n");return void this.reject(new Error(e))}return e?t!==this.expectedState?(r.writeHead(400),r.end("Invalid state parameter"),void this.reject(new Error("Invalid state parameter"))):(this.pendingResponse=r,void this.resolve(e)):(r.writeHead(400),r.end("Authorization code not found"),void this.reject(new Error("No authorization code received")))}handleError(e){s(e),this.close(),this.reject(e)}resolve(e){this.promiseResolver&&(this.promiseResolver(e),this.promiseResolver=null,this.promiseRejecter=null)}reject(e){this.promiseRejecter&&(this.promiseRejecter(e),this.promiseResolver=null,this.promiseRejecter=null)}close(){this.port>0&&AuthCodeListener.activeByPort.delete(this.port),this.pendingResponse&&this.handleErrorRedirect(),this.localServer&&(this.localServer.removeAllListeners(),"function"==typeof this.localServer.closeAllConnections&&this.localServer.closeAllConnections(),this.localServer.close())}}
@@ -1 +1 @@
1
- import e from"axios";import{logEvent as t}from"../analytics/index.js";import{ALL_OAUTH_SCOPES as o,CLAUDE_AI_INFERENCE_SCOPE as a,CLAUDE_AI_OAUTH_SCOPES as n,getOauthConfig as r,getOpenAIOAuthConfig as i}from"../../constants/oauth.js";import{checkAndRefreshOAuthTokenIfNeeded as s,getClaudeAIOAuthTokens as c,hasProfileScope as u,isClaudeAISubscriber as d,saveApiKey as p}from"../../utils/auth.js";import{getGlobalConfig as l,saveGlobalConfig as _}from"../../utils/config.js";import{logForDebugging as h}from"../../utils/debug.js";import{getOauthProfileFromOauthToken as A}from"./getOauthProfile.js";export function shouldUseClaudeAIAuth(e){return Boolean(e?.includes(a))}export function parseScopes(e){return e?.split(" ").filter(Boolean)??[]}function getProviderConfig(e){if("openai"===e){const e=i();if(!e)throw new Error("OpenAI OAuth is not configured. Set OPENAI_OAUTH_AUTHORIZE_URL, OPENAI_OAUTH_TOKEN_URL, OPENAI_OAUTH_CLIENT_ID, and OPENAI_OAUTH_MANUAL_REDIRECT_URL.");return e}const t=r();return{AUTHORIZE_URL:t.CLAUDE_AI_AUTHORIZE_URL,TOKEN_URL:t.TOKEN_URL,CLIENT_ID:t.CLIENT_ID,MANUAL_REDIRECT_URL:t.MANUAL_REDIRECT_URL,SUCCESS_URL:t.CLAUDEAI_SUCCESS_URL,FILE_SUFFIX:t.OAUTH_FILE_SUFFIX,BASE_API_URL:t.BASE_API_URL,PROFILE_URL:`${t.BASE_API_URL}/api/oauth/profile`,API_KEY_URL:t.API_KEY_URL,ROLES_URL:t.ROLES_URL}}export function getOAuthRequestDetails({port:e,isManual:t,provider:n="anthropic",inferenceOnly:i,loginWithClaudeAi:s}){const c=getProviderConfig(n),u="openai"===n?c.AUTHORIZE_URL:s?r().CLAUDE_AI_AUTHORIZE_URL:r().CONSOLE_AUTHORIZE_URL,d=t?c.MANUAL_REDIRECT_URL:function(e,t,o){return"openai"===e&&t.LOCAL_REDIRECT_URL?t.LOCAL_REDIRECT_URL:`http://localhost:${o}${t.CALLBACK_PATH??"/callback"}`}(n,c,e),p=i?[a]:"openai"===n?c.SCOPES??[]:o;return{authorizeUrl:u,tokenUrl:c.TOKEN_URL,redirectUri:d,clientId:c.CLIENT_ID,scopes:p}}export function buildAuthUrl({codeChallenge:e,state:t,port:o,isManual:a,loginWithClaudeAi:n,provider:r="anthropic",inferenceOnly:i,orgUUID:s,loginHint:c,loginMethod:u}){getProviderConfig(r);const d=getOAuthRequestDetails({port:o,isManual:a,provider:r,inferenceOnly:i,loginWithClaudeAi:n}),p=new URL(d.authorizeUrl);return"openai"!==r&&p.searchParams.append("code","true"),p.searchParams.append("client_id",d.clientId),p.searchParams.append("response_type","code"),p.searchParams.append("redirect_uri",d.redirectUri),p.searchParams.append("scope",d.scopes.join(" ")),p.searchParams.append("code_challenge",e),p.searchParams.append("code_challenge_method","S256"),p.searchParams.append("state",t),"openai"===r&&(p.searchParams.append("id_token_add_organizations","true"),p.searchParams.append("codex_cli_simplified_flow","true"),p.searchParams.append("originator","pi")),s&&p.searchParams.append("orgUUID",s),c&&p.searchParams.append("login_hint",c),u&&p.searchParams.append("login_method",u),p.toString()}export async function exchangeCodeForTokens(o,a,n,r,i=!1,s,c="anthropic"){const u=getOAuthRequestDetails({port:r,isManual:i,provider:c}),d={grant_type:"authorization_code",code:o,redirect_uri:u.redirectUri,client_id:u.clientId,code_verifier:n};let p;"openai"!==c&&(d.state=a),void 0!==s&&(d.expires_in=s);try{p="openai"===c?await e.post(u.tokenUrl,new URLSearchParams(Object.entries(d).map(([e,t])=>[e,String(t)])),{headers:{"Content-Type":"application/x-www-form-urlencoded"},timeout:15e3}):await e.post(u.tokenUrl,d,{headers:{"Content-Type":"application/json"},timeout:15e3})}catch(t){if(e.isAxiosError(t)){const e=t.response?.status,o="string"==typeof t.response?.data?t.response.data:JSON.stringify(t.response?.data??{}),a=["Token exchange failed"+(e?` (${e})`:""),`redirect_uri=${u.redirectUri}`,`client_id=${u.clientId}`,`scope=${u.scopes.join(" ")}`,o&&"{}"!==o?`response=${o}`:""].filter(Boolean);throw new Error(a.join("\n"))}throw t}if(200!==p.status)throw new Error(401===p.status?"Authentication failed: Invalid authorization code":`Token exchange failed (${p.status}): ${p.statusText}`);return t("tengu_oauth_token_exchange_success",{}),p.data}export async function refreshOAuthToken(o,{scopes:a}={}){const i={grant_type:"refresh_token",refresh_token:o,client_id:r().CLIENT_ID,scope:(a?.length?a:n).join(" ")};try{const a=await e.post(r().TOKEN_URL,i,{headers:{"Content-Type":"application/json"},timeout:15e3});if(200!==a.status)throw new Error(`Token refresh failed: ${a.statusText}`);const n=a.data,{access_token:s,refresh_token:u=o,expires_in:d}=n,p=Date.now()+1e3*d,h=parseScopes(n.scope);t("tengu_oauth_token_refresh_success",{});const A=l(),g=c(),U=void 0!==A.oauthAccount?.billingType&&void 0!==A.oauthAccount?.accountCreatedAt&&void 0!==A.oauthAccount?.subscriptionCreatedAt&&null!=g?.subscriptionType&&null!=g?.rateLimitTier?null:await fetchProfileInfo(s);if(U&&A.oauthAccount){const e={};void 0!==U.displayName&&(e.displayName=U.displayName),"boolean"==typeof U.hasExtraUsageEnabled&&(e.hasExtraUsageEnabled=U.hasExtraUsageEnabled),null!==U.billingType&&(e.billingType=U.billingType),void 0!==U.accountCreatedAt&&(e.accountCreatedAt=U.accountCreatedAt),void 0!==U.subscriptionCreatedAt&&(e.subscriptionCreatedAt=U.subscriptionCreatedAt),Object.keys(e).length>0&&_(t=>({...t,oauthAccount:t.oauthAccount?{...t.oauthAccount,...e}:t.oauthAccount}))}return{accessToken:s,refreshToken:u,expiresAt:p,scopes:h,subscriptionType:U?.subscriptionType??g?.subscriptionType??null,rateLimitTier:U?.rateLimitTier??g?.rateLimitTier??null,profile:U?.rawProfile,tokenAccount:n.account?{uuid:n.account.uuid,emailAddress:n.account.email_address,organizationUuid:n.organization?.uuid}:void 0}}catch(o){const a=e.isAxiosError(o)&&o.response?.data?JSON.stringify(o.response.data):void 0;throw t("tengu_oauth_token_refresh_failure",{error:o.message,...a&&{responseBody:a}}),o}}export async function refreshOpenAIOAuthToken(o,{scopes:a}={}){const n=getProviderConfig("openai"),r={grant_type:"refresh_token",refresh_token:o,client_id:n.CLIENT_ID,...a?.length||n.SCOPES?.length?{scope:(a?.length?a:n.SCOPES??[]).join(" ")}:{}};try{const t=await e.post(n.TOKEN_URL,r,{headers:{"Content-Type":"application/json"},timeout:15e3});if(200!==t.status)throw new Error(`OpenAI token refresh failed: ${t.statusText}`);const a=t.data,{access_token:i,refresh_token:s=o,expires_in:c}=a;return{accessToken:i,refreshToken:s,expiresAt:c?Date.now()+1e3*c:null,scopes:parseScopes(a.scope),subscriptionType:null,rateLimitTier:null,tokenAccount:a.account?{uuid:a.account.uuid,emailAddress:a.account.email_address,organizationUuid:a.organization?.uuid}:void 0}}catch(o){const a=e.isAxiosError(o)&&o.response?.data?JSON.stringify(o.response.data):void 0;throw t("tengu_openai_oauth_token_refresh_failure",{error:o.message,...a&&{responseBody:a}}),o}}export async function fetchAndStoreUserRoles(o){const a=await e.get(r().ROLES_URL,{headers:{Authorization:`Bearer ${o}`}});if(200!==a.status)throw new Error(`Failed to fetch user roles: ${a.statusText}`);const n=a.data;if(!l().oauthAccount)throw new Error("OAuth account information not found in config");_(e=>({...e,oauthAccount:e.oauthAccount?{...e.oauthAccount,organizationRole:n.organization_role,workspaceRole:n.workspace_role,organizationName:n.organization_name}:e.oauthAccount})),t("tengu_oauth_roles_stored",{org_role:n.organization_role})}export async function createAndStoreApiKey(o){try{const a=await e.post(r().API_KEY_URL,null,{headers:{Authorization:`Bearer ${o}`}}),n=a.data?.raw_key;return n?(await p(n),t("tengu_oauth_api_key",{status:"success",statusCode:a.status}),n):null}catch(e){throw t("tengu_oauth_api_key",{status:"failure",error:e instanceof Error?e.message:String(e)}),e}}export function isOAuthTokenExpired(e){if(null===e)return!1;return Date.now()+3e5>=e}export async function fetchProfileInfo(e){const o=await A(e),a=o?.organization?.organization_type;let n=null;switch(a){case"claude_max":n="max";break;case"claude_pro":n="pro";break;case"claude_enterprise":n="enterprise";break;case"claude_team":n="team";break;default:n=null}const r={subscriptionType:n,rateLimitTier:o?.organization?.rate_limit_tier??null,hasExtraUsageEnabled:o?.organization?.has_extra_usage_enabled??null,billingType:o?.organization?.billing_type??null};return o?.account?.display_name&&(r.displayName=o.account.display_name),o?.account?.created_at&&(r.accountCreatedAt=o.account.created_at),o?.organization?.subscription_created_at&&(r.subscriptionCreatedAt=o.organization.subscription_created_at),t("tengu_oauth_profile_fetch_success",{}),{...r,rawProfile:o}}export async function getOrganizationUUID(){const e=l(),t=e.oauthAccount?.organizationUuid;if(t)return t;const o=c()?.accessToken;if(void 0===o||!u())return null;const a=await A(o),n=a?.organization?.uuid;return n||null}export async function populateOAuthAccountInfoIfNeeded(){const e=process.env.CONTEXT_CODE_ACCOUNT_UUID??process.env.CLAUDE_CODE_ACCOUNT_UUID,t=process.env.CONTEXT_CODE_USER_EMAIL??process.env.CLAUDE_CODE_USER_EMAIL,o=process.env.CONTEXT_CODE_ORGANIZATION_UUID??process.env.CLAUDE_CODE_ORGANIZATION_UUID,a=Boolean(e&&t&&o);e&&t&&o&&(l().oauthAccount||storeOAuthAccountInfo({accountUuid:e,emailAddress:t,organizationUuid:o})),await s();const n=l();if(n.oauthAccount&&void 0!==n.oauthAccount.billingType&&void 0!==n.oauthAccount.accountCreatedAt&&void 0!==n.oauthAccount.subscriptionCreatedAt||!d()||!u())return!1;const r=c();if(r?.accessToken){const e=await A(r.accessToken);if(e)return a&&h("OAuth profile fetch succeeded, overriding env var account info",{level:"info"}),storeOAuthAccountInfo({accountUuid:e.account.uuid,emailAddress:e.account.email,organizationUuid:e.organization.uuid,displayName:e.account.display_name||void 0,hasExtraUsageEnabled:e.organization.has_extra_usage_enabled??!1,billingType:e.organization.billing_type??void 0,accountCreatedAt:e.account.created_at,subscriptionCreatedAt:e.organization.subscription_created_at??void 0}),!0}return!1}export function storeOAuthAccountInfo({accountUuid:e,emailAddress:t,organizationUuid:o,displayName:a,hasExtraUsageEnabled:n,billingType:r,accountCreatedAt:i,subscriptionCreatedAt:s}){const c={accountUuid:e,emailAddress:t,organizationUuid:o,hasExtraUsageEnabled:n,billingType:r,accountCreatedAt:i,subscriptionCreatedAt:s};a&&(c.displayName=a),_(e=>e.oauthAccount?.accountUuid===c.accountUuid&&e.oauthAccount?.emailAddress===c.emailAddress&&e.oauthAccount?.organizationUuid===c.organizationUuid&&e.oauthAccount?.displayName===c.displayName&&e.oauthAccount?.hasExtraUsageEnabled===c.hasExtraUsageEnabled&&e.oauthAccount?.billingType===c.billingType&&e.oauthAccount?.accountCreatedAt===c.accountCreatedAt&&e.oauthAccount?.subscriptionCreatedAt===c.subscriptionCreatedAt?e:{...e,oauthAccount:c})}
1
+ import e from"axios";import{createAxiosInstance as t}from"../../utils/proxy.js";import{logEvent as o}from"../analytics/index.js";import{ALL_OAUTH_SCOPES as a,CLAUDE_AI_INFERENCE_SCOPE as n,CLAUDE_AI_OAUTH_SCOPES as r,getOauthConfig as i,getOpenAIOAuthConfig as s,getOpenAIOriginator as c}from"../../constants/oauth.js";import{checkAndRefreshOAuthTokenIfNeeded as u,getClaudeAIOAuthTokens as d,hasProfileScope as p,isClaudeAISubscriber as l,saveApiKey as _}from"../../utils/auth.js";import{getGlobalConfig as h,saveGlobalConfig as A}from"../../utils/config.js";import{logForDebugging as g}from"../../utils/debug.js";import{getOauthProfileFromOauthToken as f}from"./getOauthProfile.js";export function shouldUseClaudeAIAuth(e){return Boolean(e?.includes(n))}export function parseScopes(e){return e?.split(" ").filter(Boolean)??[]}function getProviderConfig(e){if("openai"===e){const e=s();if(!e)throw new Error("OpenAI OAuth is not configured. Set OPENAI_OAUTH_AUTHORIZE_URL, OPENAI_OAUTH_TOKEN_URL, OPENAI_OAUTH_CLIENT_ID, and OPENAI_OAUTH_MANUAL_REDIRECT_URL.");return e}const t=i();return{AUTHORIZE_URL:t.CLAUDE_AI_AUTHORIZE_URL,TOKEN_URL:t.TOKEN_URL,CLIENT_ID:t.CLIENT_ID,MANUAL_REDIRECT_URL:t.MANUAL_REDIRECT_URL,SUCCESS_URL:t.CLAUDEAI_SUCCESS_URL,FILE_SUFFIX:t.OAUTH_FILE_SUFFIX,BASE_API_URL:t.BASE_API_URL,PROFILE_URL:`${t.BASE_API_URL}/api/oauth/profile`,API_KEY_URL:t.API_KEY_URL,ROLES_URL:t.ROLES_URL}}export function getOAuthRequestDetails({port:e,isManual:t,provider:o="anthropic",inferenceOnly:r,loginWithClaudeAi:s}){const c=getProviderConfig(o),u="openai"===o?c.AUTHORIZE_URL:s?i().CLAUDE_AI_AUTHORIZE_URL:i().CONSOLE_AUTHORIZE_URL,d=t?c.MANUAL_REDIRECT_URL:function(e,t,o){return"openai"===e&&t.LOCAL_REDIRECT_URL?t.LOCAL_REDIRECT_URL:`http://localhost:${o}${t.CALLBACK_PATH??"/callback"}`}(o,c,e),p=r?[n]:"openai"===o?c.SCOPES??[]:a;return{authorizeUrl:u,tokenUrl:c.TOKEN_URL,redirectUri:d,clientId:c.CLIENT_ID,scopes:p}}export function buildAuthUrl({codeChallenge:e,state:t,port:o,isManual:a,loginWithClaudeAi:n,provider:r="anthropic",inferenceOnly:i,orgUUID:s,loginHint:u,loginMethod:d}){getProviderConfig(r);const p=getOAuthRequestDetails({port:o,isManual:a,provider:r,inferenceOnly:i,loginWithClaudeAi:n}),l=new URL(p.authorizeUrl);return"openai"!==r&&l.searchParams.append("code","true"),l.searchParams.append("client_id",p.clientId),l.searchParams.append("response_type","code"),l.searchParams.append("redirect_uri",p.redirectUri),l.searchParams.append("scope",p.scopes.join(" ")),l.searchParams.append("code_challenge",e),l.searchParams.append("code_challenge_method","S256"),l.searchParams.append("state",t),"openai"===r&&(l.searchParams.append("id_token_add_organizations","true"),l.searchParams.append("codex_cli_simplified_flow","true"),l.searchParams.append("originator",c())),s&&l.searchParams.append("orgUUID",s),u&&l.searchParams.append("login_hint",u),d&&l.searchParams.append("login_method",d),l.toString()}export async function exchangeCodeForTokens(a,n,r,i,s=!1,c,u="anthropic"){const d=getOAuthRequestDetails({port:i,isManual:s,provider:u}),p={grant_type:"authorization_code",code:a,redirect_uri:d.redirectUri,client_id:d.clientId,code_verifier:r};let l;"openai"!==u&&(p.state=n),void 0!==c&&(p.expires_in=c);try{l="openai"===u?await t().post(d.tokenUrl,new URLSearchParams(Object.entries(p).map(([e,t])=>[e,String(t)])),{headers:{"Content-Type":"application/x-www-form-urlencoded"},timeout:15e3}):await t().post(d.tokenUrl,p,{headers:{"Content-Type":"application/json"},timeout:15e3})}catch(t){if(e.isAxiosError(t)){const e=t.response?.status,o="string"==typeof t.response?.data?t.response.data:JSON.stringify(t.response?.data??{}),a=["Token exchange failed"+(e?` (${e})`:""),`redirect_uri=${d.redirectUri}`,`client_id=${d.clientId}`,`scope=${d.scopes.join(" ")}`,o&&"{}"!==o?`response=${o}`:""].filter(Boolean);throw new Error(a.join("\n"))}throw t}if(200!==l.status)throw new Error(401===l.status?"Authentication failed: Invalid authorization code":`Token exchange failed (${l.status}): ${l.statusText}`);return o("tengu_oauth_token_exchange_success",{}),l.data}export async function refreshOAuthToken(a,{scopes:n}={}){const s={grant_type:"refresh_token",refresh_token:a,client_id:i().CLIENT_ID,scope:(n?.length?n:r).join(" ")};try{const e=await t().post(i().TOKEN_URL,s,{headers:{"Content-Type":"application/json"},timeout:15e3});if(200!==e.status)throw new Error(`Token refresh failed: ${e.statusText}`);const n=e.data,{access_token:r,refresh_token:c=a,expires_in:u}=n,p=Date.now()+1e3*u,l=parseScopes(n.scope);o("tengu_oauth_token_refresh_success",{});const _=h(),g=d(),f=void 0!==_.oauthAccount?.billingType&&void 0!==_.oauthAccount?.accountCreatedAt&&void 0!==_.oauthAccount?.subscriptionCreatedAt&&null!=g?.subscriptionType&&null!=g?.rateLimitTier?null:await fetchProfileInfo(r);if(f&&_.oauthAccount){const e={};void 0!==f.displayName&&(e.displayName=f.displayName),"boolean"==typeof f.hasExtraUsageEnabled&&(e.hasExtraUsageEnabled=f.hasExtraUsageEnabled),null!==f.billingType&&(e.billingType=f.billingType),void 0!==f.accountCreatedAt&&(e.accountCreatedAt=f.accountCreatedAt),void 0!==f.subscriptionCreatedAt&&(e.subscriptionCreatedAt=f.subscriptionCreatedAt),Object.keys(e).length>0&&A(t=>({...t,oauthAccount:t.oauthAccount?{...t.oauthAccount,...e}:t.oauthAccount}))}return{accessToken:r,refreshToken:c,expiresAt:p,scopes:l,subscriptionType:f?.subscriptionType??g?.subscriptionType??null,rateLimitTier:f?.rateLimitTier??g?.rateLimitTier??null,profile:f?.rawProfile,tokenAccount:n.account?{uuid:n.account.uuid,emailAddress:n.account.email_address,organizationUuid:n.organization?.uuid}:void 0}}catch(t){const a=e.isAxiosError(t)&&t.response?.data?JSON.stringify(t.response.data):void 0;throw o("tengu_oauth_token_refresh_failure",{error:t.message,...a&&{responseBody:a}}),t}}export async function refreshOpenAIOAuthToken(a,{scopes:n}={}){const r=getProviderConfig("openai"),i={grant_type:"refresh_token",refresh_token:a,client_id:r.CLIENT_ID,...n?.length||r.SCOPES?.length?{scope:(n?.length?n:r.SCOPES??[]).join(" ")}:{}};try{const e=await t().post(r.TOKEN_URL,i,{headers:{"Content-Type":"application/json"},timeout:15e3});if(200!==e.status)throw new Error(`OpenAI token refresh failed: ${e.statusText}`);const o=e.data,{access_token:n,refresh_token:s=a,expires_in:c}=o;return{accessToken:n,refreshToken:s,expiresAt:c?Date.now()+1e3*c:null,scopes:parseScopes(o.scope),subscriptionType:null,rateLimitTier:null,tokenAccount:o.account?{uuid:o.account.uuid,emailAddress:o.account.email_address,organizationUuid:o.organization?.uuid}:void 0}}catch(t){const a=e.isAxiosError(t)&&t.response?.data?JSON.stringify(t.response.data):void 0;throw o("tengu_openai_oauth_token_refresh_failure",{error:t.message,...a&&{responseBody:a}}),t}}export async function fetchAndStoreUserRoles(e){const a=await t().get(i().ROLES_URL,{headers:{Authorization:`Bearer ${e}`}});if(200!==a.status)throw new Error(`Failed to fetch user roles: ${a.statusText}`);const n=a.data;if(!h().oauthAccount)throw new Error("OAuth account information not found in config");A(e=>({...e,oauthAccount:e.oauthAccount?{...e.oauthAccount,organizationRole:n.organization_role,workspaceRole:n.workspace_role,organizationName:n.organization_name}:e.oauthAccount})),o("tengu_oauth_roles_stored",{org_role:n.organization_role})}export async function createAndStoreApiKey(e){try{const a=await t().post(i().API_KEY_URL,null,{headers:{Authorization:`Bearer ${e}`}}),n=a.data?.raw_key;return n?(await _(n),o("tengu_oauth_api_key",{status:"success",statusCode:a.status}),n):null}catch(e){throw o("tengu_oauth_api_key",{status:"failure",error:e instanceof Error?e.message:String(e)}),e}}export function isOAuthTokenExpired(e){if(null===e)return!1;return Date.now()+3e5>=e}export async function fetchProfileInfo(e){const t=await f(e),a=t?.organization?.organization_type;let n=null;switch(a){case"claude_max":n="max";break;case"claude_pro":n="pro";break;case"claude_enterprise":n="enterprise";break;case"claude_team":n="team";break;default:n=null}const r={subscriptionType:n,rateLimitTier:t?.organization?.rate_limit_tier??null,hasExtraUsageEnabled:t?.organization?.has_extra_usage_enabled??null,billingType:t?.organization?.billing_type??null};return t?.account?.display_name&&(r.displayName=t.account.display_name),t?.account?.created_at&&(r.accountCreatedAt=t.account.created_at),t?.organization?.subscription_created_at&&(r.subscriptionCreatedAt=t.organization.subscription_created_at),o("tengu_oauth_profile_fetch_success",{}),{...r,rawProfile:t}}export async function getOrganizationUUID(){const e=h(),t=e.oauthAccount?.organizationUuid;if(t)return t;const o=d()?.accessToken;if(void 0===o||!p())return null;const a=await f(o),n=a?.organization?.uuid;return n||null}export async function populateOAuthAccountInfoIfNeeded(){const e=process.env.CONTEXT_CODE_ACCOUNT_UUID??process.env.CLAUDE_CODE_ACCOUNT_UUID,t=process.env.CONTEXT_CODE_USER_EMAIL??process.env.CLAUDE_CODE_USER_EMAIL,o=process.env.CONTEXT_CODE_ORGANIZATION_UUID??process.env.CLAUDE_CODE_ORGANIZATION_UUID,a=Boolean(e&&t&&o);e&&t&&o&&(h().oauthAccount||storeOAuthAccountInfo({accountUuid:e,emailAddress:t,organizationUuid:o})),await u();const n=h();if(n.oauthAccount&&void 0!==n.oauthAccount.billingType&&void 0!==n.oauthAccount.accountCreatedAt&&void 0!==n.oauthAccount.subscriptionCreatedAt||!l()||!p())return!1;const r=d();if(r?.accessToken){const e=await f(r.accessToken);if(e)return a&&g("OAuth profile fetch succeeded, overriding env var account info",{level:"info"}),storeOAuthAccountInfo({accountUuid:e.account.uuid,emailAddress:e.account.email,organizationUuid:e.organization.uuid,displayName:e.account.display_name||void 0,hasExtraUsageEnabled:e.organization.has_extra_usage_enabled??!1,billingType:e.organization.billing_type??void 0,accountCreatedAt:e.account.created_at,subscriptionCreatedAt:e.organization.subscription_created_at??void 0}),!0}return!1}export function storeOAuthAccountInfo({accountUuid:e,emailAddress:t,organizationUuid:o,displayName:a,hasExtraUsageEnabled:n,billingType:r,accountCreatedAt:i,subscriptionCreatedAt:s}){const c={accountUuid:e,emailAddress:t,organizationUuid:o,hasExtraUsageEnabled:n,billingType:r,accountCreatedAt:i,subscriptionCreatedAt:s};a&&(c.displayName=a),A(e=>e.oauthAccount?.accountUuid===c.accountUuid&&e.oauthAccount?.emailAddress===c.emailAddress&&e.oauthAccount?.organizationUuid===c.organizationUuid&&e.oauthAccount?.displayName===c.displayName&&e.oauthAccount?.hasExtraUsageEnabled===c.hasExtraUsageEnabled&&e.oauthAccount?.billingType===c.billingType&&e.oauthAccount?.accountCreatedAt===c.accountCreatedAt&&e.oauthAccount?.subscriptionCreatedAt===c.subscriptionCreatedAt?e:{...e,oauthAccount:c})}
@@ -1 +1 @@
1
- import{createHash as e,randomBytes as t}from"node:crypto";import{GEMINI_CLI_OAUTH_AUTHORIZE_URL as a,GEMINI_CLI_OAUTH_CALLBACK_PATH as r,GEMINI_CLI_OAUTH_CALLBACK_PORT as o,GEMINI_CLI_OAUTH_CLIENT_ID as s,GEMINI_CLI_OAUTH_CLIENT_SECRET as n,GEMINI_CLI_OAUTH_REDIRECT_URI as i,GEMINI_CLI_OAUTH_SCOPES as c,GEMINI_CLI_OAUTH_TOKEN_URL as l}from"../../constants/geminiOAuth.js";import{openBrowser as d}from"../../utils/browser.js";import{logForDebugging as p}from"../../utils/debug.js";import{AuthCodeListener as h}from"./auth-code-listener.js";function base64Url(e){return e.toString("base64").replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/g,"")}export async function startGeminiCliOAuthFlow(){const m=new h(r),u=base64Url(t(32)),f=(y=u,base64Url(e("sha256").update(y).digest()));var y;const _=t(16).toString("hex");await m.start(o,"localhost");const w=new URL(a);w.searchParams.set("client_id",s),w.searchParams.set("redirect_uri",i),w.searchParams.set("response_type","code"),w.searchParams.set("scope",c.join(" ")),w.searchParams.set("state",_),w.searchParams.set("code_challenge",f),w.searchParams.set("code_challenge_method","S256"),w.searchParams.set("access_type","offline"),w.searchParams.set("prompt","consent");try{const e=await m.waitForAuthorization(_,async()=>{await d(w.toString())}),t=await fetch(l,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:new URLSearchParams({grant_type:"authorization_code",code:e,redirect_uri:i,client_id:s,client_secret:n,code_verifier:u})});if(!t.ok){const e=await t.text().catch(()=>t.statusText);throw new Error(`Gemini CLI OAuth token exchange failed: ${e}`)}const a=await t.json(),r=await async function(e){const t=process.env.GEMINI_GOOGLE_PROJECT_ID?.trim()||void 0;try{const a=await fetch("https://cloudcode-pa.googleapis.com/v1internal:loadCodeAssist",{method:"POST",headers:{Authorization:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({cloudaicompanionProject:t,metadata:{ideType:"IDE_UNSPECIFIED",platform:"PLATFORM_UNSPECIFIED",pluginType:"GEMINI",duetProject:t}})});if(a.ok)return(await a.json()).cloudaicompanionProject}catch(e){p(`Gemini CLI project discovery failed: ${String(e)}`,{level:"debug"})}return t}(a.access_token);return m.handleSuccessRedirect([],"openai",e=>{e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end('<html><body style="font-family:sans-serif;padding:2rem;text-align:center"><h2>Conectado a Gemini</h2><p>Puedes cerrar esta ventana y volver a Context Code.</p></body></html>')}),{accessToken:a.access_token,refreshToken:a.refresh_token??null,expiresAt:a.expires_in?Date.now()+1e3*a.expires_in:null,scopes:a.scope?.split(/\s+/).filter(Boolean)??c,subscriptionType:null,rateLimitTier:null,projectId:r}}finally{m.close()}}
1
+ import{createHash as e,randomBytes as t}from"node:crypto";import{GEMINI_CLI_OAUTH_AUTHORIZE_URL as a,GEMINI_CLI_OAUTH_CALLBACK_PATH as r,GEMINI_CLI_OAUTH_CALLBACK_PORT as o,GEMINI_CLI_OAUTH_CLIENT_ID as s,GEMINI_CLI_OAUTH_CLIENT_SECRET as i,GEMINI_CLI_OAUTH_REDIRECT_URI as n,GEMINI_CLI_OAUTH_SCOPES as c,GEMINI_CLI_OAUTH_TOKEN_URL as l}from"../../constants/geminiOAuth.js";import{openBrowser as p}from"../../utils/browser.js";import{logForDebugging as d}from"../../utils/debug.js";import{AuthCodeListener as m}from"./auth-code-listener.js";import{createAxiosInstance as u}from"../../utils/proxy.js";function base64Url(e){return e.toString("base64").replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/g,"")}export async function startGeminiCliOAuthFlow(){const h=new m(r),f=base64Url(t(32)),_=(y=f,base64Url(e("sha256").update(y).digest()));var y;const g=t(16).toString("hex");await h.start(o,"localhost");const P=new URL(a);P.searchParams.set("client_id",s),P.searchParams.set("redirect_uri",n),P.searchParams.set("response_type","code"),P.searchParams.set("scope",c.join(" ")),P.searchParams.set("state",g),P.searchParams.set("code_challenge",_),P.searchParams.set("code_challenge_method","S256"),P.searchParams.set("access_type","offline"),P.searchParams.set("prompt","consent");try{const e=await h.waitForAuthorization(g,async()=>{await p(P.toString())}),t=(await u().post(l,new URLSearchParams({grant_type:"authorization_code",code:e,redirect_uri:n,client_id:s,client_secret:i,code_verifier:f}),{headers:{"Content-Type":"application/x-www-form-urlencoded"},timeout:15e3})).data,a=await async function(e){const t=process.env.GEMINI_GOOGLE_PROJECT_ID?.trim()||void 0;try{const a=await u().post("https://cloudcode-pa.googleapis.com/v1internal:loadCodeAssist",{cloudaicompanionProject:t,metadata:{ideType:"IDE_UNSPECIFIED",platform:"PLATFORM_UNSPECIFIED",pluginType:"GEMINI",duetProject:t}},{headers:{Authorization:`Bearer ${e}`,"Content-Type":"application/json"},timeout:15e3});if(200===a.status)return a.data.cloudaicompanionProject}catch(e){d(`Gemini CLI project discovery failed: ${String(e)}`,{level:"debug"})}return t}(t.access_token);return h.handleSuccessRedirect([],"openai",e=>{e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end('<html><body style="font-family:sans-serif;padding:2rem;text-align:center"><h2>Conectado a Gemini</h2><p>Puedes cerrar esta ventana y volver a Context Code.</p></body></html>')}),{accessToken:t.access_token,refreshToken:t.refresh_token??null,expiresAt:t.expires_in?Date.now()+1e3*t.expires_in:null,scopes:t.scope?.split(/\s+/).filter(Boolean)??c,subscriptionType:null,rateLimitTier:null,projectId:a}}finally{h.close()}}
@@ -1 +1 @@
1
- import{MACRO as e}from"../recovery/bunBundleShim.js";import r from"chalk";import{exec as t}from"child_process";import{execa as n}from"execa";import{mkdir as o,stat as s}from"fs/promises";import i from"lodash-es/memoize.js";import{CLAUDE_AI_PROFILE_SCOPE as c}from"../constants/oauth.js";import{logEvent as a}from"../services/analytics/index.js";import{GEMINI_CLI_OAUTH_CLIENT_ID as u,GEMINI_CLI_OAUTH_CLIENT_SECRET as p,GEMINI_CLI_OAUTH_SCOPES as l,GEMINI_CLI_OAUTH_TOKEN_URL as A}from"../constants/geminiOAuth.js";import{getModelStrings as d}from"./model/modelStrings.js";import{getAPIProvider as f,isOpenAICompatibleProvider as h}from"./model/providers.js";import{getResolvedProviderProfileId as _,ensureProviderProfile as g,isDefaultProfileId as O,isProfiledProvider as T,resolveProviderProfile as E}from"./model/providerProfiles.js";import{getIsNonInteractiveSession as m,preferThirdPartyAuthentication as y}from"../bootstrap/state.js";import{getMockSubscriptionType as k,shouldUseMockSubscription as C}from"../services/mockRateLimits.js";import{isOAuthTokenExpired as v,refreshOpenAIOAuthToken as I,refreshOAuthToken as K,shouldUseClaudeAIAuth as S}from"../services/oauth/client.js";import{getOauthProfileFromOauthToken as x}from"../services/oauth/getOauthProfile.js";import{getApiKeyFromFileDescriptor as P,getOAuthTokenFromFileDescriptor as w}from"./authFileDescriptor.js";import{maybeRemoveApiKeyFromMacOSKeychainThrows as N,normalizeApiKeyForConfig as R}from"./authPortable.js";import{checkStsCallerIdentity as D,clearAwsIniCache as H,isValidAwsStsOutput as U}from"./aws.js";import{AwsAuthStatusManager as b}from"./awsAuthStatusManager.js";import{clearBetasCaches as L}from"./betas.js";import{checkHasTrustDialogAccepted as G,getGlobalConfig as j,saveGlobalConfig as F}from"./config.js";import{logAntError as M,logForDebugging as $}from"./debug.js";import{getClaudeConfigHomeDir as Y,isBareMode as B,isEnvTruthy as X,isRunningOnHomespace as W}from"./envUtils.js";import{errorMessage as z}from"./errors.js";import{execSyncWithDefaults_DEPRECATED as q}from"./execFileNoThrow.js";import*as V from"./lockfile.js";import{logError as J}from"./log.js";import{memoizeWithTTLAsync as Z}from"./memoize.js";import{getSecureStorage as Q}from"./secureStorage/index.js";import{clearLegacyApiKeyPrefetch as ee,getLegacyApiKeyPrefetchResult as re}from"./secureStorage/keychainPrefetch.js";import{clearKeychainCache as te,getMacOsKeychainStorageServiceName as ne,getUsername as oe}from"./secureStorage/macOsKeychainHelpers.js";import{getLegacyCredentialsFilePath as se,getSecureStorageDbPath as ie}from"./secureStorage/sqliteStorage.js";import{getSettings_DEPRECATED as ce,getSettingsForSource as ae}from"./settings/settings.js";import{sleep as ue}from"./sleep.js";import{jsonParse as pe}from"./slowOperations.js";import{clearToolSchemaCache as le}from"./toolSchemaCache.js";function isManagedOAuthContext(){return X(process.env.CONTEXT_CODE_REMOTE)||X(process.env.CLAUDE_CODE_REMOTE)||"claude-desktop"===process.env.CLAUDE_CODE_ENTRYPOINT}export function isAnthropicAuthEnabled(){if(B())return!1;if(process.env.ANTHROPIC_UNIX_SOCKET)return!(!process.env.CONTEXT_CODE_OAUTH_TOKEN&&!process.env.CLAUDE_CODE_OAUTH_TOKEN);const e=f(),r=X(process.env.CONTEXT_CODE_USE_BEDROCK)||X(process.env.CLAUDE_CODE_USE_BEDROCK)||X(process.env.CONTEXT_CODE_USE_VERTEX)||X(process.env.CLAUDE_CODE_USE_VERTEX)||X(process.env.CONTEXT_CODE_USE_FOUNDRY)||X(process.env.CLAUDE_CODE_USE_FOUNDRY)||h(e),t=(ce()||{}).apiKeyHelper,n=process.env.ANTHROPIC_AUTH_TOKEN||t||process.env.CONTEXT_CODE_API_KEY_FILE_DESCRIPTOR||process.env.CLAUDE_CODE_API_KEY_FILE_DESCRIPTOR,{source:o}=getAnthropicApiKeyWithSource({skipRetrievingKeyFromApiKeyHelper:!0}),s="ANTHROPIC_API_KEY"===o||"apiKeyHelper"===o;return!(r||n&&!isManagedOAuthContext()||s&&!isManagedOAuthContext())}export function getAuthTokenSource(){const e=f();if(h(e))return{source:e,hasToken:Boolean(getOpenAICompatibleAccessToken(e))};if(B())return getConfiguredApiKeyHelper()?{source:"apiKeyHelper",hasToken:!0}:{source:"none",hasToken:!1};if(process.env.ANTHROPIC_AUTH_TOKEN&&!isManagedOAuthContext())return{source:"ANTHROPIC_AUTH_TOKEN",hasToken:!0};if(isManagedOAuthContext()&&(process.env.CONTEXT_CODE_OAUTH_TOKEN||process.env.CLAUDE_CODE_OAUTH_TOKEN))return{source:"CLAUDE_CODE_OAUTH_TOKEN",hasToken:!0};if(isManagedOAuthContext()?w():null)return process.env.CONTEXT_CODE_OAUTH_TOKEN_FILE_DESCRIPTOR||process.env.CLAUDE_CODE_OAUTH_TOKEN_FILE_DESCRIPTOR?{source:"CLAUDE_CODE_OAUTH_TOKEN_FILE_DESCRIPTOR",hasToken:!0}:{source:"CCR_OAUTH_TOKEN_FILE",hasToken:!0};if(getConfiguredApiKeyHelper()&&!isManagedOAuthContext())return{source:"apiKeyHelper",hasToken:!0};const r=getClaudeAIOAuthTokens();return S(r?.scopes)&&r?.accessToken?{source:"claude.ai",hasToken:!0}:{source:"none",hasToken:!1}}function getProviderOauthStorageKey(e){return"claude"===e?"claudeAiOauth":"openAiOauth"}function shouldUseLegacyProviderOauthFallback(e){return"claude"!==e}export function getStoredProviderOAuthTokens(e,r){try{const t=Q().read();if(r){const n=t?.providerProfileOauth?.[r];if(n?.accessToken)return n;if(!O(e,r))return null}if("gemini-google"===e)return null;if(!shouldUseLegacyProviderOauthFallback(e))return null;const n=t?.[getProviderOauthStorageKey(e)];return n?.accessToken?n:null}catch{return null}}export function hasStoredProviderOAuthTokens(e,r){if(r)return Boolean(getStoredProviderOAuthTokens(e,r));try{const r=Q().read(),t=Object.entries(r?.providerProfileOauth??{}).some(([r,t])=>r.startsWith(`${e}/`)&&"object"==typeof t&&null!==t&&"string"==typeof t.accessToken&&t.accessToken.trim());return shouldUseLegacyProviderOauthFallback(e)?Boolean(t||r?.[getProviderOauthStorageKey(e)]?.accessToken):Boolean(t)}catch{return!1}}export async function renameProviderScopedCredentials(e,r){if(!e||!r||e===r)return;const t=Q(),n=t.read()||{},o={...n.providerProfileApiKeys??{}},s={...n.providerProfileOauth??{}};e in o&&(o[r]=o[e],delete o[e]),e in s&&(s[r]=s[e],delete s[e]);if(!t.update({...n,providerProfileApiKeys:o,providerProfileOauth:s}).success)throw new Error("No se pudieron mover las credenciales del perfil.")}export async function removeProviderScopedCredentials(e){if(!e)return;const r=Q(),t=r.read()||{},n={...t.providerProfileApiKeys??{}},o={...t.providerProfileOauth??{}};delete n[e],delete o[e];if(!r.update({...t,providerProfileApiKeys:n,providerProfileOauth:o}).success)throw new Error("No se pudieron eliminar las credenciales del perfil.")}export async function removeAllProviderScopedCredentials(){const e=Q(),r=e.read()||{};if(!e.update({...r,providerProfileApiKeys:{},providerProfileOauth:{}}).success)throw new Error("No se pudieron eliminar las credenciales scoped de perfiles.")}export function getAnthropicApiKey(){const{key:e}=getAnthropicApiKeyWithSource();return e}export function hasAnthropicApiKeyAuth(){const{key:e,source:r}=getAnthropicApiKeyWithSource({skipRetrievingKeyFromApiKeyHelper:!0});return null!==e&&"none"!==r}export function getAnthropicApiKeyWithSource(e={}){if(h(f()))return{key:null,source:"none"};if(B())return process.env.ANTHROPIC_API_KEY?{key:process.env.ANTHROPIC_API_KEY,source:"ANTHROPIC_API_KEY"}:getConfiguredApiKeyHelper()?{key:e.skipRetrievingKeyFromApiKeyHelper?null:getApiKeyFromApiKeyHelperCached(),source:"apiKeyHelper"}:{key:null,source:"none"};const r=W()?void 0:process.env.ANTHROPIC_API_KEY;if(y()&&r)return{key:r,source:"ANTHROPIC_API_KEY"};if(X(process.env.CI)||"test"===process.env.NODE_ENV){const e=P();if(e)return{key:e,source:"ANTHROPIC_API_KEY"};if(!(r||process.env.CONTEXT_CODE_OAUTH_TOKEN||process.env.CLAUDE_CODE_OAUTH_TOKEN||process.env.CONTEXT_CODE_OAUTH_TOKEN_FILE_DESCRIPTOR||process.env.CLAUDE_CODE_OAUTH_TOKEN_FILE_DESCRIPTOR))throw new Error("ANTHROPIC_API_KEY or CONTEXT_CODE_OAUTH_TOKEN (legacy: CLAUDE_CODE_OAUTH_TOKEN) env var is required");return r?{key:r,source:"ANTHROPIC_API_KEY"}:{key:null,source:"none"}}if(r&&j().customApiKeyResponses?.approved?.includes(R(r)))return{key:r,source:"ANTHROPIC_API_KEY"};const t=P();if(t)return{key:t,source:"ANTHROPIC_API_KEY"};if(getConfiguredApiKeyHelper())return e.skipRetrievingKeyFromApiKeyHelper?{key:null,source:"apiKeyHelper"}:{key:getApiKeyFromApiKeyHelperCached(),source:"apiKeyHelper"};const n=getApiKeyFromConfigOrMacOSKeychain();return n||{key:null,source:"none"}}export function getConfiguredApiKeyHelper(){if(B())return ae("flagSettings")?.apiKeyHelper;return(ce()||{}).apiKeyHelper}function isApiKeyHelperFromProjectOrLocalSettings(){const e=getConfiguredApiKeyHelper();if(!e)return!1;const r=ae("projectSettings"),t=ae("localSettings");return r?.apiKeyHelper===e||t?.apiKeyHelper===e}function getConfiguredAwsAuthRefresh(){return(ce()||{}).awsAuthRefresh}export function isAwsAuthRefreshFromProjectSettings(){const e=getConfiguredAwsAuthRefresh();if(!e)return!1;const r=ae("projectSettings"),t=ae("localSettings");return r?.awsAuthRefresh===e||t?.awsAuthRefresh===e}function getConfiguredAwsCredentialExport(){return(ce()||{}).awsCredentialExport}export function isAwsCredentialExportFromProjectSettings(){const e=getConfiguredAwsCredentialExport();if(!e)return!1;const r=ae("projectSettings"),t=ae("localSettings");return r?.awsCredentialExport===e||t?.awsCredentialExport===e}export function calculateApiKeyHelperTTL(){const e=process.env.CONTEXT_CODE_API_KEY_HELPER_TTL_MS??process.env.CLAUDE_CODE_API_KEY_HELPER_TTL_MS;if(e){const r=parseInt(e,10);if(!Number.isNaN(r)&&r>=0)return r;$(`Found CLAUDE_CODE_API_KEY_HELPER_TTL_MS env var, but it was not a valid number. Got ${e}`,{level:"error"})}return 3e5}let Ae=null,de=null,fe=0;export function getApiKeyHelperElapsedMs(){const e=de?.startedAt;return e?Date.now()-e:0}export async function getApiKeyFromApiKeyHelper(e){if(!getConfiguredApiKeyHelper())return null;const r=calculateApiKeyHelperTTL();return Ae?(Date.now()-Ae.timestamp<r||de||(de={promise:_runAndCache(e,!1,fe),startedAt:null}),Ae.value):(de||(de={promise:_runAndCache(e,!0,fe),startedAt:Date.now()}),de.promise)}async function _runAndCache(t,o,s){try{const r=await async function(r){const t=getConfiguredApiKeyHelper();if(!t)return null;if(isApiKeyHelperFromProjectOrLocalSettings()){if(!G()&&!r){const r=new Error(`Security: apiKeyHelper executed before workspace trust is confirmed. If you see this message, post in ${e.FEEDBACK_CHANNEL}.`);return M("apiKeyHelper invoked before trust check",r),a("tengu_apiKeyHelper_missing_trust11",{}),null}}const o=await n(t,{shell:!0,timeout:6e5,reject:!1});if(o.failed){const e=o.timedOut?"timed out":`exited ${o.exitCode}`,r=o.stderr?.trim();throw new Error(r?`${e}: ${r}`:e)}const s=o.stdout?.trim();if(!s)throw new Error("did not return a value");return s}(t);return s!==fe||null!==r&&(Ae={value:r,timestamp:Date.now()}),r}catch(e){if(s!==fe)return" ";const t=e instanceof Error?e.message:String(e);return console.error(r.red(`apiKeyHelper failed: ${t}`)),$(`Error getting API key from apiKeyHelper: ${t}`,{level:"error"}),!o&&Ae&&" "!==Ae.value?(Ae={...Ae,timestamp:Date.now()},Ae.value):(Ae={value:" ",timestamp:Date.now()}," ")}finally{s===fe&&(de=null)}}export function getApiKeyFromApiKeyHelperCached(){return Ae?.value??null}export function clearApiKeyHelperCache(){fe++,Ae=null,de=null}export function prefetchApiKeyFromApiKeyHelperIfSafe(e){isApiKeyHelperFromProjectOrLocalSettings()&&!G()||getApiKeyFromApiKeyHelper(e)}const he=18e4;export function refreshAwsAuth(e){$("Running AWS auth refresh command");const n=b.getInstance();return n.startAuthentication(),new Promise(o=>{const s=t(e,{timeout:he});s.stdout.on("data",e=>{const r=e.toString().trim();r&&(n.addOutput(r),$(r,{level:"debug"}))}),s.stderr.on("data",e=>{const r=e.toString().trim();r&&(n.setError(r),$(r,{level:"error"}))}),s.on("close",(e,t)=>{if(0===e)$("AWS auth refresh completed successfully"),n.endAuthentication(!0),o(!0);else{const e="SIGTERM"===t?r.red("AWS auth refresh timed out after 3 minutes. Run your auth command manually in a separate terminal."):r.red("Error running awsAuthRefresh (in settings or ~/.context.json):");console.error(e),n.endAuthentication(!1),o(!1)}})})}export const refreshAndGetAwsCredentials=Z(async()=>{const t=await async function(){const r=getConfiguredAwsAuthRefresh();if(!r)return!1;if(isAwsAuthRefreshFromProjectSettings()&&!G()&&!m()){const r=new Error(`Security: awsAuthRefresh executed before workspace trust is confirmed. If you see this message, post in ${e.FEEDBACK_CHANNEL}.`);return M("awsAuthRefresh invoked before trust check",r),a("tengu_awsAuthRefresh_missing_trust",{}),!1}try{return $("Fetching AWS caller identity for AWS auth refresh command"),await D(),$("Fetched AWS caller identity, skipping AWS auth refresh command"),!1}catch{return refreshAwsAuth(r)}}(),o=await async function(){const t=getConfiguredAwsCredentialExport();if(!t)return null;if(isAwsCredentialExportFromProjectSettings()&&!G()&&!m()){const r=new Error(`Security: awsCredentialExport executed before workspace trust is confirmed. If you see this message, post in ${e.FEEDBACK_CHANNEL}.`);return M("awsCredentialExport invoked before trust check",r),a("tengu_awsCredentialExport_missing_trust",{}),null}try{return $("Fetching AWS caller identity for credential export command"),await D(),$("Fetched AWS caller identity, skipping AWS credential export command"),null}catch{try{$("Running AWS credential export command");const e=await n(t,{shell:!0,reject:!1});if(0!==e.exitCode||!e.stdout)throw new Error("awsCredentialExport did not return a valid value");const r=pe(e.stdout.trim());if(!U(r))throw new Error("awsCredentialExport did not return valid AWS STS output structure");return $("AWS credentials retrieved from awsCredentialExport"),{accessKeyId:r.Credentials.AccessKeyId,secretAccessKey:r.Credentials.SecretAccessKey,sessionToken:r.Credentials.SessionToken}}catch(e){const t=r.red("Error getting AWS credentials from awsCredentialExport (in settings or ~/.context.json):");return e instanceof Error?console.error(t,e.message):console.error(t,e),null}}}();return(t||o)&&await H(),o},36e5);export function clearAwsCredentialsCache(){refreshAndGetAwsCredentials.cache.clear()}function getConfiguredGcpAuthRefresh(){return(ce()||{}).gcpAuthRefresh}export function isGcpAuthRefreshFromProjectSettings(){const e=getConfiguredGcpAuthRefresh();if(!e)return!1;const r=ae("projectSettings"),t=ae("localSettings");return r?.gcpAuthRefresh===e||t?.gcpAuthRefresh===e}const _e=l;export async function checkGcpCredentialsValid(){try{const{GoogleAuth:e}=await import("google-auth-library"),r=new e({scopes:["https://www.googleapis.com/auth/cloud-platform"]}),t=(async()=>{const e=await r.getClient();await e.getAccessToken()})(),n=ue(5e3).then(()=>{throw new GcpCredentialsTimeoutError("GCP credentials check timed out")});return await Promise.race([t,n]),!0}catch{return!1}}const ge=18e4;export function refreshGcpAuth(e){$("Running GCP auth refresh command");const n=b.getInstance();return n.startAuthentication(),new Promise(o=>{const s=t(e,{timeout:ge});s.stdout.on("data",e=>{const r=e.toString().trim();r&&(n.addOutput(r),$(r,{level:"debug"}))}),s.stderr.on("data",e=>{const r=e.toString().trim();r&&(n.setError(r),$(r,{level:"error"}))}),s.on("close",(e,t)=>{if(0===e)$("GCP auth refresh completed successfully"),n.endAuthentication(!0),o(!0);else{const e="SIGTERM"===t?r.red("GCP auth refresh timed out after 3 minutes. Run your auth command manually in a separate terminal."):r.red("Error running gcpAuthRefresh (in settings or ~/.context.json):");console.error(e),n.endAuthentication(!1),o(!1)}})})}export const refreshGcpCredentialsIfNeeded=Z(async()=>await async function(){const r=getConfiguredGcpAuthRefresh();if(!r)return!1;if(isGcpAuthRefreshFromProjectSettings()&&!G()&&!m()){const r=new Error(`Security: gcpAuthRefresh executed before workspace trust is confirmed. If you see this message, post in ${e.FEEDBACK_CHANNEL}.`);return M("gcpAuthRefresh invoked before trust check",r),a("tengu_gcpAuthRefresh_missing_trust",{}),!1}try{if($("Checking GCP credentials validity for auth refresh"),await checkGcpCredentialsValid())return $("GCP credentials are valid, skipping auth refresh command"),!1}catch{}return refreshGcpAuth(r)}(),36e5);export function clearGcpCredentialsCache(){refreshGcpCredentialsIfNeeded.cache.clear()}export function prefetchGcpCredentialsIfSafe(){if(getConfiguredGcpAuthRefresh()){if(isGcpAuthRefreshFromProjectSettings()){if(!G()&&!m())return}refreshGcpCredentialsIfNeeded()}}export function prefetchAwsCredentialsAndBedRockInfoIfSafe(){const e=getConfiguredAwsAuthRefresh(),r=getConfiguredAwsCredentialExport();if(e||r){if(isAwsAuthRefreshFromProjectSettings()||isAwsCredentialExportFromProjectSettings()){if(!G()&&!m())return}refreshAndGetAwsCredentials(),d()}}export const getApiKeyFromConfigOrMacOSKeychain=i(()=>{if("darwin"===process.platform){const e=re();if(e){if(e.stdout)return{key:e.stdout,source:"/login managed key"}}else{const e=ne();try{const r=q(`security find-generic-password -a $USER -w -s "${e}"`);if(r)return{key:r,source:"/login managed key"}}catch(e){J(e)}}}const e=j();return e.primaryApiKey?{key:e.primaryApiKey,source:"/login managed key"}:null});function isValidApiKey(e){return/^[a-zA-Z0-9-_\.]+$/.test(e)}function getStoredProviderApiKey(e,r){try{const t=Q().read();if(r){const n=t?.providerProfileApiKeys?.[r];if("string"==typeof n&&n.trim())return n;if(!O(e,r))return null}return t?.providerApiKeys?.[e]??null}catch{return null}}export function hasStoredProviderApiKey(e,r){return Boolean(getStoredProviderApiKey(e,r))}export async function saveProviderApiKey(e,r){if(!isValidApiKey(r))throw new Error("Formato de clave API inválido. La clave API solo debe contener caracteres alfanuméricos, guiones, guiones bajos y puntos.");const t=Q(),n=t.read()||{},o=T(e)?E(e,{createIfMissing:!0})?.id??null:null;if(!t.update({...n,providerApiKeys:{...n.providerApiKeys??{},[e]:r},...o?{providerProfileApiKeys:{...n.providerProfileApiKeys??{},[o]:r}}:{}}).success)throw new Error(`Failed to save ${e} API key`)}export async function removeProviderApiKey(e){const r=Q(),t=r.read()||{},n={...t.providerApiKeys??{}};delete n[e];const o={...t.providerProfileApiKeys??{}};if(T(e)){const r=_(e);r&&delete o[r]}if(!r.update({...t,providerApiKeys:n,providerProfileApiKeys:o}).success)throw new Error(`Failed to remove ${e} API key`)}export async function saveApiKey(e){if(!isValidApiKey(e))throw new Error("Formato de clave API inválido. La clave API solo debe contener caracteres alfanuméricos, guiones, guiones bajos y puntos.");await maybeRemoveApiKeyFromMacOSKeychain();let r=!1;if("darwin"===process.platform)try{const t=ne(),o=oe(),s=`add-generic-password -U -a "${o}" -s "${t}" -X "${Buffer.from(e,"utf-8").toString("hex")}"\n`;await n("security",["-i"],{input:s,reject:!1}),a("tengu_api_key_saved_to_keychain",{}),r=!0}catch(e){J(e),a("tengu_api_key_keychain_error",{error:z(e)}),a("tengu_api_key_saved_to_config",{})}else a("tengu_api_key_saved_to_config",{});const t=R(e);F(n=>{const o=n.customApiKeyResponses?.approved??[];return{...n,primaryApiKey:r?n.primaryApiKey:e,customApiKeyResponses:{...n.customApiKeyResponses,approved:o.includes(t)?o:[...o,t],rejected:n.customApiKeyResponses?.rejected??[]}}}),getApiKeyFromConfigOrMacOSKeychain.cache.clear?.(),ee()}export function isCustomApiKeyApproved(e){const r=j(),t=R(e);return r.customApiKeyResponses?.approved?.includes(t)??!1}export async function removeApiKey(){await maybeRemoveApiKeyFromMacOSKeychain(),F(e=>({...e,primaryApiKey:void 0})),getApiKeyFromConfigOrMacOSKeychain.cache.clear?.(),ee()}async function maybeRemoveApiKeyFromMacOSKeychain(){try{await N()}catch(e){J(e)}}export function saveOAuthTokensIfNeeded(e,r){if(!S(e.scopes))return a("tengu_oauth_tokens_not_claude_ai",{}),{success:!0};if(!e.refreshToken||!e.expiresAt)return a("tengu_oauth_tokens_inference_only",{}),{success:!0};const t=Q(),n=t.name;try{const o=t.read()||{},s=o.claudeAiOauth,i=r??_("claude"),c={accessToken:e.accessToken,refreshToken:e.refreshToken,expiresAt:e.expiresAt,scopes:e.scopes,subscriptionType:e.subscriptionType??s?.subscriptionType??null,rateLimitTier:e.rateLimitTier??s?.rateLimitTier??null};i&&(o.providerProfileOauth={...o.providerProfileOauth??{},[i]:c});const u=t.update(o);return u.success?a("tengu_oauth_tokens_saved",{storageBackend:n}):a("tengu_oauth_tokens_save_failed",{storageBackend:n}),getClaudeAIOAuthTokens.cache?.clear?.(),L(),le(),u}catch(e){return J(e),a("tengu_oauth_tokens_save_exception",{storageBackend:n,error:z(e)}),{success:!1,warning:"Failed to save OAuth tokens"}}}export function saveOpenAIOAuthTokens(e,r){const t=Q(),n=t.name;try{const o=t.read()||{},s=r??_("openai"),i={accessToken:e.accessToken,refreshToken:e.refreshToken,expiresAt:e.expiresAt,scopes:e.scopes,subscriptionType:e.subscriptionType??null,rateLimitTier:e.rateLimitTier??null};o.openAiOauth=i,s&&(o.providerProfileOauth={...o.providerProfileOauth??{},[s]:i});const c=t.update(o);return c.success?a("tengu_openai_oauth_tokens_saved",{storageBackend:n}):a("tengu_openai_oauth_tokens_save_failed",{storageBackend:n}),getOpenAIOAuthTokens.cache?.clear?.(),L(),le(),c}catch(e){return J(e),a("tengu_openai_oauth_tokens_save_exception",{storageBackend:n,error:z(e)}),{success:!1,warning:"Failed to save OpenAI OAuth tokens"}}}export function getClaudeAIOAuthTokens(){if(B())return null;const e=process.env.CONTEXT_CODE_OAUTH_TOKEN??process.env.CLAUDE_CODE_OAUTH_TOKEN;if(isManagedOAuthContext()&&e)return{accessToken:e,refreshToken:null,expiresAt:null,scopes:["user:inference"],subscriptionType:null,rateLimitTier:null};const r=isManagedOAuthContext()?w():null;if(r)return{accessToken:r,refreshToken:null,expiresAt:null,scopes:["user:inference"],subscriptionType:null,rateLimitTier:null};try{const e=getStoredProviderOAuthTokens("claude",_("claude"));return e?.accessToken?e:null}catch(e){return J(e),null}}export function getOpenAIOAuthTokens(){if(B())return null;if(process.env.OPENAI_OAUTH_TOKEN)return{accessToken:process.env.OPENAI_OAUTH_TOKEN,refreshToken:null,expiresAt:null,scopes:["responses:inference"],subscriptionType:null,rateLimitTier:null};try{const e=getStoredProviderOAuthTokens("openai",_("openai"));return e?.accessToken?e:null}catch(e){return J(e),null}}export function getOpenAIAccessToken(){return process.env.OPENAI_API_KEY||process.env.OPENAI_API_TOKEN||getOpenAIOAuthTokens()?.accessToken||null}export function getOpenRouterAccessToken(){return process.env.OPENROUTER_API_KEY||process.env.OPENROUTER_API_TOKEN||getStoredProviderApiKey("openrouter",_("openrouter"))||null}export async function checkGeminiGoogleCredentialsValid(){try{const e=await getGeminiGoogleAuthHeaders(),r=process.env.GEMINI_GOOGLE_PROJECT_ID?.trim()||void 0,t=fetch("https://cloudcode-pa.googleapis.com/v1internal:loadCodeAssist",{method:"POST",headers:e,body:JSON.stringify({cloudaicompanionProject:r,metadata:{ideType:"IDE_UNSPECIFIED",platform:"PLATFORM_UNSPECIFIED",pluginType:"GEMINI",duetProject:r},mode:"HEALTH_CHECK"})}).then(e=>{if(!e.ok)throw new Error(`Gemini credentials check failed: ${e.status}`)}),n=ue(5e3).then(()=>{throw new GcpCredentialsTimeoutError("Gemini credentials check timed out")});return await Promise.race([t,n]),!0}catch{return!1}}export function getGeminiGoogleOAuthTokens(){try{const e=_("gemini-google"),r=Q().read(),t=e?r?.providerProfileOauth?.[e]:null;if(t?.accessToken)return t;const n=Object.entries(r?.providerProfileOauth??{}).find(([e,r])=>e.startsWith("gemini-google/")&&"object"==typeof r&&null!==r&&"string"==typeof r.accessToken&&r.accessToken.trim())?.[1];return n?.accessToken?n:null}catch{return null}}export function saveGeminiGoogleOAuthTokens(e){const r=Q(),t=r.name;try{const n=r.read()||{},o=_("gemini-google")??g("gemini-google").id,s={accessToken:e.accessToken,refreshToken:e.refreshToken,expiresAt:e.expiresAt,scopes:e.scopes,subscriptionType:null,rateLimitTier:null,projectId:e.projectId};o&&(n.providerProfileOauth={...n.providerProfileOauth??{},[o]:s});const i=r.update(n);return a(i.success?"tengu_gemini_google_oauth_tokens_saved":"tengu_gemini_google_oauth_tokens_save_failed",{storageBackend:t}),i}catch(e){return J(e),a("tengu_gemini_google_oauth_tokens_save_exception",{storageBackend:t,error:z(e)}),{success:!1,warning:"Failed to save Gemini OAuth tokens"}}}function quoteShellArg(e){return`"${e.replace(/"/g,'\\"')}"`}export function getGeminiGoogleAuthCommand(){const e=process.env.GEMINI_OAUTH_CLIENT_SECRET_FILE||process.env.GOOGLE_OAUTH_CLIENT_SECRET_FILE,r=_e.join(",");return`gcloud auth application-default login${e?` --client-id-file=${quoteShellArg(e)}`:""} --scopes=${quoteShellArg(r)}`}export async function refreshGeminiGoogleAuth(){return refreshGcpAuth(getGeminiGoogleAuthCommand())}export function getGeminiApiAccessToken(){return process.env.GEMINI_API_KEY||process.env.GOOGLE_API_KEY||getStoredProviderApiKey("gemini-api",_("gemini-api"))||null}export async function getGeminiGoogleAuthHeaders(){const e=process.env.GEMINI_OAUTH_TOKEN||process.env.GOOGLE_OAUTH_ACCESS_TOKEN,r={"Content-Type":"application/json"};if(e)r.Authorization=`Bearer ${e}`;else{const e=await async function(){const e=getGeminiGoogleOAuthTokens();if(!e?.refreshToken)return e;if(e.expiresAt&&e.expiresAt>Date.now()+6e4)return e;const r=await fetch(A,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:new URLSearchParams({grant_type:"refresh_token",refresh_token:e.refreshToken,client_id:u,client_secret:p})});if(!r.ok)return e;const t=await r.json(),n={...e,accessToken:t.access_token,expiresAt:t.expires_in?Date.now()+1e3*t.expires_in:e.expiresAt,scopes:t.scope?.split(/\s+/).filter(Boolean)??e.scopes};return saveGeminiGoogleOAuthTokens(n),n}();if(e?.accessToken){r.Authorization=`Bearer ${e.accessToken}`;const t=process.env.GEMINI_GOOGLE_PROJECT_ID?.trim();t&&(r["x-goog-user-project"]=t)}else{const{GoogleAuth:e}=await import("google-auth-library"),t=new e({scopes:_e}),n=await t.getClient(),o=await n.getRequestHeaders();if("function"==typeof o.forEach)o.forEach((e,t)=>{r[t]=e});else for(const[e,t]of Object.entries(o))Array.isArray(t)?r[e]=t.map(String).join(", "):null!=t&&(r[e]=String(t))}}const t=process.env.GEMINI_GOOGLE_PROJECT_ID?.trim()||void 0;return t&&(r["x-goog-user-project"]=t),r}export function getZAIAccessToken(){return process.env.ZAI_API_KEY||getStoredProviderApiKey("zai",_("zai"))||null}export function getMiniMaxAccessToken(){return process.env.MINIMAX_API_KEY||getStoredProviderApiKey("minimax",_("minimax"))||null}export function getNvidiaAccessToken(){return process.env.NVIDIA_API_KEY||getStoredProviderApiKey("nvidia",_("nvidia"))||null}export function getDeepSeekAccessToken(){return process.env.DEEPSEEK_API_KEY||getStoredProviderApiKey("deepseek",_("deepseek"))||null}export function getOllamaAccessToken(){return"ollama"}export function getOllamaCloudAccessToken(){return process.env.OLLAMA_API_KEY||getStoredProviderApiKey("ollama-cloud",_("ollama-cloud"))||null}export function getOpenAICompatibleAccessToken(e=f()){switch(e){case"openrouter":return getOpenRouterAccessToken();case"gemini-api":return getGeminiApiAccessToken();case"gemini-google":return process.env.GEMINI_OAUTH_TOKEN||process.env.GOOGLE_OAUTH_ACCESS_TOKEN||null;case"zai":return getZAIAccessToken();case"minimax":return getMiniMaxAccessToken();case"nvidia":return getNvidiaAccessToken();case"deepseek":return getDeepSeekAccessToken();case"ollama":return getOllamaAccessToken();case"ollama-cloud":return getOllamaCloudAccessToken();case"custom-openai":return getStoredProviderApiKey("custom-openai");default:return getOpenAIAccessToken()}}export async function getOpenAIOAuthTokensAsync(){if(B())return null;if(process.env.OPENAI_OAUTH_TOKEN)return getOpenAIOAuthTokens();try{const e=Q(),r=await e.readAsync(),t=_("openai"),n=t&&r?.providerProfileOauth?.[t]||(t&&!O("openai",t)?null:r?.openAiOauth);return n?.accessToken?n:null}catch(e){return J(e),null}}export function clearOAuthTokenCache(){getClaudeAIOAuthTokens.cache?.clear?.(),getOpenAIOAuthTokens.cache?.clear?.(),te()}let Oe=0;async function invalidateOAuthCacheIfDiskChanged(){try{const e="sqlite"===Q().name?ie():se(),{mtimeMs:r}=await s(e);r!==Oe&&(Oe=r,clearOAuthTokenCache())}catch{getClaudeAIOAuthTokens.cache?.clear?.(),getOpenAIOAuthTokens.cache?.clear?.()}}const Te=new Map;export function handleOAuth401Error(e){const r=Te.get(e);if(r)return r;const t=async function(e){clearOAuthTokenCache();const r=await getClaudeAIOAuthTokensAsync();if(!r?.refreshToken)return!1;if(r.accessToken!==e)return a("tengu_oauth_401_recovered_from_keychain",{}),!0;return checkAndRefreshOAuthTokenIfNeeded(0,!0)}(e).finally(()=>{Te.delete(e)});return Te.set(e,t),t}export async function handleOpenAIOAuth401Error(e){clearOAuthTokenCache();const r=await getOpenAIOAuthTokensAsync();return!!r?.refreshToken&&(r.accessToken!==e?(a("tengu_openai_oauth_401_recovered_from_keychain",{}),!0):checkAndRefreshOpenAIOAuthTokenIfNeeded(0,!0))}export async function getClaudeAIOAuthTokensAsync(){if(B())return null;if(isManagedOAuthContext()&&(process.env.CONTEXT_CODE_OAUTH_TOKEN||process.env.CLAUDE_CODE_OAUTH_TOKEN||w()))return getClaudeAIOAuthTokens();try{const e=Q(),r=await e.readAsync(),t=_("claude"),n=t&&r?.providerProfileOauth?.[t]||(t&&!O("claude",t)?null:r?.claudeAiOauth);return n?.accessToken?n:null}catch(e){return J(e),null}}let Ee=null,me=null;export function checkAndRefreshOAuthTokenIfNeeded(e=0,r=!1){if(0===e&&!r){if(Ee)return Ee;const t=checkAndRefreshOAuthTokenIfNeededImpl(e,r);return Ee=t.finally(()=>{Ee=null}),Ee}return checkAndRefreshOAuthTokenIfNeededImpl(e,r)}export function checkAndRefreshOpenAIOAuthTokenIfNeeded(e=0,r=!1){if(0===e&&!r){if(me)return me;const t=checkAndRefreshOpenAIOAuthTokenIfNeededImpl(e,r);return me=t.finally(()=>{me=null}),me}return checkAndRefreshOpenAIOAuthTokenIfNeededImpl(e,r)}async function checkAndRefreshOAuthTokenIfNeededImpl(e,r){await invalidateOAuthCacheIfDiskChanged();const t=getClaudeAIOAuthTokens();if(!(r||t?.refreshToken&&v(t.expiresAt)))return!1;if(!t?.refreshToken)return!1;if(!S(t.scopes))return!1;getClaudeAIOAuthTokens.cache?.clear?.(),te();const n=await getClaudeAIOAuthTokensAsync();if(!n?.refreshToken||!v(n.expiresAt))return!1;const s=Y();let i;await o(s,{recursive:!0});try{a("tengu_oauth_token_refresh_lock_acquiring",{}),i=await V.lock(s),a("tengu_oauth_token_refresh_lock_acquired",{})}catch(t){return"ELOCKED"===t.code?e<5?(a("tengu_oauth_token_refresh_lock_retry",{retryCount:e+1}),await ue(1e3+1e3*Math.random()),checkAndRefreshOAuthTokenIfNeededImpl(e+1,r)):(a("tengu_oauth_token_refresh_lock_retry_limit_reached",{maxRetries:5}),!1):(J(t),a("tengu_oauth_token_refresh_lock_error",{error:z(t)}),!1)}try{getClaudeAIOAuthTokens.cache?.clear?.(),te();const e=await getClaudeAIOAuthTokensAsync();if(!e?.refreshToken||!v(e.expiresAt))return a("tengu_oauth_token_refresh_race_resolved",{}),!1;a("tengu_oauth_token_refresh_starting",{});return saveOAuthTokensIfNeeded(await K(e.refreshToken,{scopes:S(e.scopes)?void 0:e.scopes})),getClaudeAIOAuthTokens.cache?.clear?.(),te(),!0}catch(e){J(e),getClaudeAIOAuthTokens.cache?.clear?.(),te();const r=await getClaudeAIOAuthTokensAsync();return!(!r||v(r.expiresAt))&&(a("tengu_oauth_token_refresh_race_recovered",{}),!0)}finally{a("tengu_oauth_token_refresh_lock_releasing",{}),await i(),a("tengu_oauth_token_refresh_lock_released",{})}}async function checkAndRefreshOpenAIOAuthTokenIfNeededImpl(e,r){await invalidateOAuthCacheIfDiskChanged();const t=getOpenAIOAuthTokens();if(!(r||t?.refreshToken&&v(t.expiresAt)))return!1;if(!t?.refreshToken)return!1;getOpenAIOAuthTokens.cache?.clear?.(),te();const n=await getOpenAIOAuthTokensAsync();if(!n?.refreshToken||!v(n.expiresAt))return!1;const s=Y();let i;await o(s,{recursive:!0});try{a("tengu_openai_oauth_token_refresh_lock_acquiring",{}),i=await V.lock(s),a("tengu_openai_oauth_token_refresh_lock_acquired",{})}catch(t){return"ELOCKED"===t.code?e<5?(a("tengu_openai_oauth_token_refresh_lock_retry",{retryCount:e+1}),await ue(1e3+1e3*Math.random()),checkAndRefreshOpenAIOAuthTokenIfNeededImpl(e+1,r)):(a("tengu_openai_oauth_token_refresh_lock_retry_limit_reached",{maxRetries:5}),!1):(J(t),!1)}try{getOpenAIOAuthTokens.cache?.clear?.(),te();const e=await getOpenAIOAuthTokensAsync();if(!e?.refreshToken||!v(e.expiresAt))return a("tengu_openai_oauth_token_refresh_race_resolved",{}),!1;a("tengu_openai_oauth_token_refresh_starting",{});return saveOpenAIOAuthTokens(await I(e.refreshToken,{scopes:e.scopes})),getOpenAIOAuthTokens.cache?.clear?.(),te(),!0}catch(e){J(e),getOpenAIOAuthTokens.cache?.clear?.(),te();const r=await getOpenAIOAuthTokensAsync();return!(!r||v(r.expiresAt))&&(a("tengu_openai_oauth_token_refresh_race_recovered",{}),!0)}finally{a("tengu_openai_oauth_token_refresh_lock_releasing",{}),await i(),a("tengu_openai_oauth_token_refresh_lock_released",{})}}export function isClaudeAISubscriber(){return!!isAnthropicAuthEnabled()&&S(getClaudeAIOAuthTokens()?.scopes)}export function hasProfileScope(){return getClaudeAIOAuthTokens()?.scopes?.includes(c)??!1}export function is1PApiCustomer(){return!(X(process.env.CONTEXT_CODE_USE_BEDROCK)||X(process.env.CLAUDE_CODE_USE_BEDROCK)||X(process.env.CONTEXT_CODE_USE_VERTEX)||X(process.env.CLAUDE_CODE_USE_VERTEX)||X(process.env.CONTEXT_CODE_USE_FOUNDRY)||X(process.env.CLAUDE_CODE_USE_FOUNDRY)||h(f()))&&!isClaudeAISubscriber()}export function getOauthAccountInfo(){return isAnthropicAuthEnabled()?j().oauthAccount:void 0}export function isOverageProvisioningAllowed(){const e=getOauthAccountInfo(),r=e?.billingType;return!(!isClaudeAISubscriber()||!r)&&("stripe_subscription"===r||"stripe_subscription_contracted"===r||"apple_subscription"===r||"google_play_subscription"===r)}export function hasOpusAccess(){const e=getSubscriptionType();return"max"===e||"enterprise"===e||"team"===e||"pro"===e||null===e}export function getSubscriptionType(){if(C())return k();if(!isAnthropicAuthEnabled())return null;const e=getClaudeAIOAuthTokens();return e?e.subscriptionType??null:null}export function isMaxSubscriber(){return"max"===getSubscriptionType()}export function isTeamSubscriber(){return"team"===getSubscriptionType()}export function isTeamPremiumSubscriber(){return"team"===getSubscriptionType()&&"default_claude_max_5x"===getRateLimitTier()}export function isEnterpriseSubscriber(){return"enterprise"===getSubscriptionType()}export function isProSubscriber(){return"pro"===getSubscriptionType()}export function getRateLimitTier(){if(!isAnthropicAuthEnabled())return null;const e=getClaudeAIOAuthTokens();return e?e.rateLimitTier??null:null}export function getSubscriptionName(){switch(getSubscriptionType()){case"enterprise":return"Context Empresarial";case"team":return"Context Equipo";case"max":return"Context Max";case"pro":return"Context Pro";default:return"Context API"}}export function isUsing3PServices(){return!!(X(process.env.CONTEXT_CODE_USE_BEDROCK)||X(process.env.CLAUDE_CODE_USE_BEDROCK)||X(process.env.CONTEXT_CODE_USE_VERTEX)||X(process.env.CLAUDE_CODE_USE_VERTEX)||X(process.env.CONTEXT_CODE_USE_FOUNDRY)||X(process.env.CLAUDE_CODE_USE_FOUNDRY)||h(f()))}function getConfiguredOtelHeadersHelper(){return(ce()||{}).otelHeadersHelper}export function isOtelHeadersHelperFromProjectOrLocalSettings(){const e=getConfiguredOtelHeadersHelper();if(!e)return!1;const r=ae("projectSettings"),t=ae("localSettings");return r?.otelHeadersHelper===e||t?.otelHeadersHelper===e}let ye=null,ke=0;const Ce=174e4;export function getOtelHeadersFromHelper(){const e=getConfiguredOtelHeadersHelper();if(!e)return{};const r=parseInt(process.env.CONTEXT_CODE_OTEL_HEADERS_HELPER_DEBOUNCE_MS||process.env.CLAUDE_CODE_OTEL_HEADERS_HELPER_DEBOUNCE_MS||Ce.toString());if(ye&&Date.now()-ke<r)return ye;if(isOtelHeadersHelperFromProjectOrLocalSettings()){if(!G())return{}}try{const r=q(e,{timeout:3e4})?.toString().trim();if(!r)throw new Error("otelHeadersHelper did not return a valid value");const t=pe(r);if("object"!=typeof t||null===t||Array.isArray(t))throw new Error("otelHeadersHelper must return a JSON object with string key-value pairs");for(const[e,r]of Object.entries(t))if("string"!=typeof r)throw new Error(`otelHeadersHelper returned non-string value for key "${e}": ${typeof r}`);return ye=t,ke=Date.now(),ye}catch(e){throw J(new Error(`Error getting OpenTelemetry headers from otelHeadersHelper (in settings): ${z(e)}`)),e}}export function isConsumerSubscriber(){const e=getSubscriptionType();return isClaudeAISubscriber()&&null!==e&&("max"===(r=e)||"pro"===r);var r}export function getAccountInformation(){if("firstParty"!==f())return;const{source:e}=getAuthTokenSource(),r={};"CLAUDE_CODE_OAUTH_TOKEN"===e||"CLAUDE_CODE_OAUTH_TOKEN_FILE_DESCRIPTOR"===e?r.tokenSource=e:isClaudeAISubscriber()?r.subscription=getSubscriptionName():r.tokenSource=e;const{key:t,source:n}=getAnthropicApiKeyWithSource();if(t&&(r.apiKeySource=n),"claude.ai"===e||"/login managed key"===n){const e=getOauthAccountInfo()?.organizationName;e&&(r.organization=e)}const o=getOauthAccountInfo()?.emailAddress;return"claude.ai"!==e&&"/login managed key"!==n||!o||(r.email=o),r}export async function validateForceLoginOrg(){if(process.env.ANTHROPIC_UNIX_SOCKET)return{valid:!0};if(!isAnthropicAuthEnabled())return{valid:!0};const e=ae("policySettings")?.forceLoginOrgUUID;if(!e)return{valid:!0};await checkAndRefreshOAuthTokenIfNeeded();const r=getClaudeAIOAuthTokens();if(!r)return{valid:!0};const{source:t}=getAuthTokenSource(),n="CLAUDE_CODE_OAUTH_TOKEN"===t||"CLAUDE_CODE_OAUTH_TOKEN_FILE_DESCRIPTOR"===t,o=await x(r.accessToken);if(!o)return{valid:!1,message:`Unable to verify organization for the current authentication token.\nThis machine requires organization ${e} but the profile could not be fetched.\nThis may be a network error, or the token may lack the user:profile scope required for\nverification (tokens from 'context setup-token' do not include this scope).\nTry again, or obtain a full-scope token via 'context auth login'.`};const s=o.organization.uuid;if(s===e)return{valid:!0};if(n){return{valid:!1,message:`The ${"CLAUDE_CODE_OAUTH_TOKEN"===t?"CLAUDE_CODE_OAUTH_TOKEN":"CLAUDE_CODE_OAUTH_TOKEN_FILE_DESCRIPTOR"} environment variable provides a token for a\ndifferent organization than required by this machine's managed settings.\n\nRequired organization: ${e}\nToken organization: ${s}\n\nRemove the environment variable or obtain a token for the correct organization.`}}return{valid:!1,message:`Your authentication token belongs to organization ${s},\nbut this machine requires organization ${e}.\n\nPlease log in with the correct organization: context auth login`}}class GcpCredentialsTimeoutError extends Error{}
1
+ import{MACRO as e}from"../recovery/bunBundleShim.js";import r from"chalk";import{exec as t}from"child_process";import{execa as n}from"execa";import{mkdir as o,stat as s}from"fs/promises";import i from"lodash-es/memoize.js";import{CLAUDE_AI_PROFILE_SCOPE as c}from"../constants/oauth.js";import{logEvent as a}from"../services/analytics/index.js";import{GEMINI_CLI_OAUTH_CLIENT_ID as u,GEMINI_CLI_OAUTH_CLIENT_SECRET as p,GEMINI_CLI_OAUTH_SCOPES as l,GEMINI_CLI_OAUTH_TOKEN_URL as A}from"../constants/geminiOAuth.js";import{getModelStrings as d}from"./model/modelStrings.js";import{getAPIProvider as f,isOpenAICompatibleProvider as h}from"./model/providers.js";import{getResolvedProviderProfileId as _,ensureProviderProfile as g,isDefaultProfileId as O,isProfiledProvider as E,resolveProviderProfile as T}from"./model/providerProfiles.js";import{getIsNonInteractiveSession as m,preferThirdPartyAuthentication as y}from"../bootstrap/state.js";import{getMockSubscriptionType as k,shouldUseMockSubscription as C}from"../services/mockRateLimits.js";import{isOAuthTokenExpired as v,refreshOpenAIOAuthToken as I,refreshOAuthToken as K,shouldUseClaudeAIAuth as S}from"../services/oauth/client.js";import{getOauthProfileFromOauthToken as P}from"../services/oauth/getOauthProfile.js";import{getApiKeyFromFileDescriptor as x,getOAuthTokenFromFileDescriptor as w}from"./authFileDescriptor.js";import{maybeRemoveApiKeyFromMacOSKeychainThrows as N,normalizeApiKeyForConfig as R}from"./authPortable.js";import{checkStsCallerIdentity as D,clearAwsIniCache as H,isValidAwsStsOutput as U}from"./aws.js";import{AwsAuthStatusManager as b}from"./awsAuthStatusManager.js";import{clearBetasCaches as L}from"./betas.js";import{checkHasTrustDialogAccepted as G,getGlobalConfig as j,saveGlobalConfig as F}from"./config.js";import{logAntError as M,logForDebugging as Y}from"./debug.js";import{getClaudeConfigHomeDir as $,isBareMode as X,isEnvTruthy as B,isRunningOnHomespace as z}from"./envUtils.js";import{errorMessage as W}from"./errors.js";import{execSyncWithDefaults_DEPRECATED as q}from"./execFileNoThrow.js";import*as V from"./lockfile.js";import{logError as J}from"./log.js";import{memoizeWithTTLAsync as Z}from"./memoize.js";import{getSecureStorage as Q}from"./secureStorage/index.js";import{clearLegacyApiKeyPrefetch as ee,getLegacyApiKeyPrefetchResult as re}from"./secureStorage/keychainPrefetch.js";import{clearKeychainCache as te,getMacOsKeychainStorageServiceName as ne,getUsername as oe}from"./secureStorage/macOsKeychainHelpers.js";import{getLegacyCredentialsFilePath as se,getSecureStorageDbPath as ie}from"./secureStorage/sqliteStorage.js";import{getSettings_DEPRECATED as ce,getSettingsForSource as ae}from"./settings/settings.js";import{sleep as ue}from"./sleep.js";import{jsonParse as pe}from"./slowOperations.js";import{clearToolSchemaCache as le}from"./toolSchemaCache.js";function isManagedOAuthContext(){return B(process.env.CONTEXT_CODE_REMOTE)||B(process.env.CLAUDE_CODE_REMOTE)||"claude-desktop"===process.env.CLAUDE_CODE_ENTRYPOINT}export function isAnthropicAuthEnabled(){if(X())return!1;if(process.env.ANTHROPIC_UNIX_SOCKET)return!(!process.env.CONTEXT_CODE_OAUTH_TOKEN&&!process.env.CLAUDE_CODE_OAUTH_TOKEN);const e=f(),r=B(process.env.CONTEXT_CODE_USE_BEDROCK)||B(process.env.CLAUDE_CODE_USE_BEDROCK)||B(process.env.CONTEXT_CODE_USE_VERTEX)||B(process.env.CLAUDE_CODE_USE_VERTEX)||B(process.env.CONTEXT_CODE_USE_FOUNDRY)||B(process.env.CLAUDE_CODE_USE_FOUNDRY)||h(e)||"custom-anthropic"===e,t=(ce()||{}).apiKeyHelper,n=process.env.ANTHROPIC_AUTH_TOKEN||t||process.env.CONTEXT_CODE_API_KEY_FILE_DESCRIPTOR||process.env.CLAUDE_CODE_API_KEY_FILE_DESCRIPTOR,{source:o}=getAnthropicApiKeyWithSource({skipRetrievingKeyFromApiKeyHelper:!0}),s="ANTHROPIC_API_KEY"===o||"apiKeyHelper"===o;return!(r||n&&!isManagedOAuthContext()||s&&!isManagedOAuthContext())}export function getAuthTokenSource(){const e=f();if(h(e))return{source:e,hasToken:Boolean(getOpenAICompatibleAccessToken(e))};if(X())return getConfiguredApiKeyHelper()?{source:"apiKeyHelper",hasToken:!0}:{source:"none",hasToken:!1};if(process.env.ANTHROPIC_AUTH_TOKEN&&!isManagedOAuthContext())return{source:"ANTHROPIC_AUTH_TOKEN",hasToken:!0};if(isManagedOAuthContext()&&(process.env.CONTEXT_CODE_OAUTH_TOKEN||process.env.CLAUDE_CODE_OAUTH_TOKEN))return{source:"CLAUDE_CODE_OAUTH_TOKEN",hasToken:!0};if(isManagedOAuthContext()?w():null)return process.env.CONTEXT_CODE_OAUTH_TOKEN_FILE_DESCRIPTOR||process.env.CLAUDE_CODE_OAUTH_TOKEN_FILE_DESCRIPTOR?{source:"CLAUDE_CODE_OAUTH_TOKEN_FILE_DESCRIPTOR",hasToken:!0}:{source:"CCR_OAUTH_TOKEN_FILE",hasToken:!0};if(getConfiguredApiKeyHelper()&&!isManagedOAuthContext())return{source:"apiKeyHelper",hasToken:!0};const r=getClaudeAIOAuthTokens();return S(r?.scopes)&&r?.accessToken?{source:"claude.ai",hasToken:!0}:{source:"none",hasToken:!1}}const Ae={gmi:"GMI_API_KEY",novita:"NOVITA_API_KEY",stepfun:"STEPFUN_API_KEY",huggingface:"HF_TOKEN","opencode-zen":"OPENCODE_ZEN_API_KEY",arcee:"ARCEEAI_API_KEY",alibaba:"DASHSCOPE_API_KEY",kimi:"KIMI_API_KEY"};function getProviderOauthStorageKey(e){return"claude"===e?"claudeAiOauth":"openAiOauth"}function shouldUseLegacyProviderOauthFallback(e){return"claude"!==e}export function getStoredProviderOAuthTokens(e,r){try{const t=Q().read();if(r){const n=t?.providerProfileOauth?.[r];if(n?.accessToken)return n;if(!O(e,r)&&!shouldUseLegacyProviderOauthFallback(e))return null}if("gemini-google"===e)return null;if(!shouldUseLegacyProviderOauthFallback(e))return null;const n=t?.[getProviderOauthStorageKey(e)];return n?.accessToken?n:null}catch{return null}}export function hasStoredProviderOAuthTokens(e,r){if(r)return Boolean(getStoredProviderOAuthTokens(e,r));try{const r=Q().read(),t=Object.entries(r?.providerProfileOauth??{}).some(([r,t])=>r.startsWith(`${e}/`)&&"object"==typeof t&&null!==t&&"string"==typeof t.accessToken&&t.accessToken.trim());return shouldUseLegacyProviderOauthFallback(e)?Boolean(t||r?.[getProviderOauthStorageKey(e)]?.accessToken):Boolean(t)}catch{return!1}}export async function renameProviderScopedCredentials(e,r){if(!e||!r||e===r)return;const t=Q(),n=t.read()||{},o={...n.providerProfileApiKeys??{}},s={...n.providerProfileOauth??{}};e in o&&(o[r]=o[e],delete o[e]),e in s&&(s[r]=s[e],delete s[e]);if(!t.update({...n,providerProfileApiKeys:o,providerProfileOauth:s}).success)throw new Error("No se pudieron mover las credenciales del perfil.")}export async function removeProviderScopedCredentials(e){if(!e)return;const r=Q(),t=r.read()||{},n={...t.providerProfileApiKeys??{}},o={...t.providerProfileOauth??{}};delete n[e],delete o[e];if(!r.update({...t,providerProfileApiKeys:n,providerProfileOauth:o}).success)throw new Error("No se pudieron eliminar las credenciales del perfil.")}export async function removeAllProviderScopedCredentials(){const e=Q(),r=e.read()||{};if(!e.update({...r,providerProfileApiKeys:{},providerProfileOauth:{}}).success)throw new Error("No se pudieron eliminar las credenciales scoped de perfiles.")}export function getAnthropicApiKey(){const{key:e}=getAnthropicApiKeyWithSource();return e}export function hasAnthropicApiKeyAuth(){const{key:e,source:r}=getAnthropicApiKeyWithSource({skipRetrievingKeyFromApiKeyHelper:!0});return null!==e&&"none"!==r}export function getAnthropicApiKeyWithSource(e={}){if(h(f()))return{key:null,source:"none"};if(X())return process.env.ANTHROPIC_API_KEY?{key:process.env.ANTHROPIC_API_KEY,source:"ANTHROPIC_API_KEY"}:getConfiguredApiKeyHelper()?{key:e.skipRetrievingKeyFromApiKeyHelper?null:getApiKeyFromApiKeyHelperCached(),source:"apiKeyHelper"}:{key:null,source:"none"};const r=z()?void 0:process.env.ANTHROPIC_API_KEY;if(y()&&r)return{key:r,source:"ANTHROPIC_API_KEY"};if(B(process.env.CI)||"test"===process.env.NODE_ENV){const e=x();if(e)return{key:e,source:"ANTHROPIC_API_KEY"};if(!(r||process.env.CONTEXT_CODE_OAUTH_TOKEN||process.env.CLAUDE_CODE_OAUTH_TOKEN||process.env.CONTEXT_CODE_OAUTH_TOKEN_FILE_DESCRIPTOR||process.env.CLAUDE_CODE_OAUTH_TOKEN_FILE_DESCRIPTOR))throw new Error("ANTHROPIC_API_KEY or CONTEXT_CODE_OAUTH_TOKEN (legacy: CLAUDE_CODE_OAUTH_TOKEN) env var is required");return r?{key:r,source:"ANTHROPIC_API_KEY"}:{key:null,source:"none"}}if(r&&j().customApiKeyResponses?.approved?.includes(R(r)))return{key:r,source:"ANTHROPIC_API_KEY"};const t=x();if(t)return{key:t,source:"ANTHROPIC_API_KEY"};if(getConfiguredApiKeyHelper())return e.skipRetrievingKeyFromApiKeyHelper?{key:null,source:"apiKeyHelper"}:{key:getApiKeyFromApiKeyHelperCached(),source:"apiKeyHelper"};const n=getApiKeyFromConfigOrMacOSKeychain();return n||{key:null,source:"none"}}export function getConfiguredApiKeyHelper(){if(X())return ae("flagSettings")?.apiKeyHelper;return(ce()||{}).apiKeyHelper}function isApiKeyHelperFromProjectOrLocalSettings(){const e=getConfiguredApiKeyHelper();if(!e)return!1;const r=ae("projectSettings"),t=ae("localSettings");return r?.apiKeyHelper===e||t?.apiKeyHelper===e}function getConfiguredAwsAuthRefresh(){return(ce()||{}).awsAuthRefresh}export function isAwsAuthRefreshFromProjectSettings(){const e=getConfiguredAwsAuthRefresh();if(!e)return!1;const r=ae("projectSettings"),t=ae("localSettings");return r?.awsAuthRefresh===e||t?.awsAuthRefresh===e}function getConfiguredAwsCredentialExport(){return(ce()||{}).awsCredentialExport}export function isAwsCredentialExportFromProjectSettings(){const e=getConfiguredAwsCredentialExport();if(!e)return!1;const r=ae("projectSettings"),t=ae("localSettings");return r?.awsCredentialExport===e||t?.awsCredentialExport===e}export function calculateApiKeyHelperTTL(){const e=process.env.CONTEXT_CODE_API_KEY_HELPER_TTL_MS??process.env.CLAUDE_CODE_API_KEY_HELPER_TTL_MS;if(e){const r=parseInt(e,10);if(!Number.isNaN(r)&&r>=0)return r;Y(`Found CLAUDE_CODE_API_KEY_HELPER_TTL_MS env var, but it was not a valid number. Got ${e}`,{level:"error"})}return 3e5}let de=null,fe=null,he=0;export function getApiKeyHelperElapsedMs(){const e=fe?.startedAt;return e?Date.now()-e:0}export async function getApiKeyFromApiKeyHelper(e){if(!getConfiguredApiKeyHelper())return null;const r=calculateApiKeyHelperTTL();return de?(Date.now()-de.timestamp<r||fe||(fe={promise:_runAndCache(e,!1,he),startedAt:null}),de.value):(fe||(fe={promise:_runAndCache(e,!0,he),startedAt:Date.now()}),fe.promise)}async function _runAndCache(t,o,s){try{const r=await async function(r){const t=getConfiguredApiKeyHelper();if(!t)return null;if(isApiKeyHelperFromProjectOrLocalSettings()){if(!G()&&!r){const r=new Error(`Security: apiKeyHelper executed before workspace trust is confirmed. If you see this message, post in ${e.FEEDBACK_CHANNEL}.`);return M("apiKeyHelper invoked before trust check",r),a("tengu_apiKeyHelper_missing_trust11",{}),null}}const o=await n(t,{shell:!0,timeout:6e5,reject:!1});if(o.failed){const e=o.timedOut?"timed out":`exited ${o.exitCode}`,r=o.stderr?.trim();throw new Error(r?`${e}: ${r}`:e)}const s=o.stdout?.trim();if(!s)throw new Error("did not return a value");return s}(t);return s!==he||null!==r&&(de={value:r,timestamp:Date.now()}),r}catch(e){if(s!==he)return" ";const t=e instanceof Error?e.message:String(e);return console.error(r.red(`apiKeyHelper failed: ${t}`)),Y(`Error getting API key from apiKeyHelper: ${t}`,{level:"error"}),!o&&de&&" "!==de.value?(de={...de,timestamp:Date.now()},de.value):(de={value:" ",timestamp:Date.now()}," ")}finally{s===he&&(fe=null)}}export function getApiKeyFromApiKeyHelperCached(){return de?.value??null}export function clearApiKeyHelperCache(){he++,de=null,fe=null}export function prefetchApiKeyFromApiKeyHelperIfSafe(e){isApiKeyHelperFromProjectOrLocalSettings()&&!G()||getApiKeyFromApiKeyHelper(e)}const _e=18e4;export function refreshAwsAuth(e){Y("Running AWS auth refresh command");const n=b.getInstance();return n.startAuthentication(),new Promise(o=>{const s=t(e,{timeout:_e});s.stdout.on("data",e=>{const r=e.toString().trim();r&&(n.addOutput(r),Y(r,{level:"debug"}))}),s.stderr.on("data",e=>{const r=e.toString().trim();r&&(n.setError(r),Y(r,{level:"error"}))}),s.on("close",(e,t)=>{if(0===e)Y("AWS auth refresh completed successfully"),n.endAuthentication(!0),o(!0);else{const e="SIGTERM"===t?r.red("AWS auth refresh timed out after 3 minutes. Run your auth command manually in a separate terminal."):r.red("Error running awsAuthRefresh (in settings or ~/.context.json):");console.error(e),n.endAuthentication(!1),o(!1)}})})}export const refreshAndGetAwsCredentials=Z(async()=>{const t=await async function(){const r=getConfiguredAwsAuthRefresh();if(!r)return!1;if(isAwsAuthRefreshFromProjectSettings()&&!G()&&!m()){const r=new Error(`Security: awsAuthRefresh executed before workspace trust is confirmed. If you see this message, post in ${e.FEEDBACK_CHANNEL}.`);return M("awsAuthRefresh invoked before trust check",r),a("tengu_awsAuthRefresh_missing_trust",{}),!1}try{return Y("Fetching AWS caller identity for AWS auth refresh command"),await D(),Y("Fetched AWS caller identity, skipping AWS auth refresh command"),!1}catch{return refreshAwsAuth(r)}}(),o=await async function(){const t=getConfiguredAwsCredentialExport();if(!t)return null;if(isAwsCredentialExportFromProjectSettings()&&!G()&&!m()){const r=new Error(`Security: awsCredentialExport executed before workspace trust is confirmed. If you see this message, post in ${e.FEEDBACK_CHANNEL}.`);return M("awsCredentialExport invoked before trust check",r),a("tengu_awsCredentialExport_missing_trust",{}),null}try{return Y("Fetching AWS caller identity for credential export command"),await D(),Y("Fetched AWS caller identity, skipping AWS credential export command"),null}catch{try{Y("Running AWS credential export command");const e=await n(t,{shell:!0,reject:!1});if(0!==e.exitCode||!e.stdout)throw new Error("awsCredentialExport did not return a valid value");const r=pe(e.stdout.trim());if(!U(r))throw new Error("awsCredentialExport did not return valid AWS STS output structure");return Y("AWS credentials retrieved from awsCredentialExport"),{accessKeyId:r.Credentials.AccessKeyId,secretAccessKey:r.Credentials.SecretAccessKey,sessionToken:r.Credentials.SessionToken}}catch(e){const t=r.red("Error getting AWS credentials from awsCredentialExport (in settings or ~/.context.json):");return e instanceof Error?console.error(t,e.message):console.error(t,e),null}}}();return(t||o)&&await H(),o},36e5);export function clearAwsCredentialsCache(){refreshAndGetAwsCredentials.cache.clear()}function getConfiguredGcpAuthRefresh(){return(ce()||{}).gcpAuthRefresh}export function isGcpAuthRefreshFromProjectSettings(){const e=getConfiguredGcpAuthRefresh();if(!e)return!1;const r=ae("projectSettings"),t=ae("localSettings");return r?.gcpAuthRefresh===e||t?.gcpAuthRefresh===e}const ge=l;export async function checkGcpCredentialsValid(){try{const{GoogleAuth:e}=await import("google-auth-library"),r=new e({scopes:["https://www.googleapis.com/auth/cloud-platform"]}),t=(async()=>{const e=await r.getClient();await e.getAccessToken()})(),n=ue(5e3).then(()=>{throw new GcpCredentialsTimeoutError("GCP credentials check timed out")});return await Promise.race([t,n]),!0}catch{return!1}}const Oe=18e4;export function refreshGcpAuth(e){Y("Running GCP auth refresh command");const n=b.getInstance();return n.startAuthentication(),new Promise(o=>{const s=t(e,{timeout:Oe});s.stdout.on("data",e=>{const r=e.toString().trim();r&&(n.addOutput(r),Y(r,{level:"debug"}))}),s.stderr.on("data",e=>{const r=e.toString().trim();r&&(n.setError(r),Y(r,{level:"error"}))}),s.on("close",(e,t)=>{if(0===e)Y("GCP auth refresh completed successfully"),n.endAuthentication(!0),o(!0);else{const e="SIGTERM"===t?r.red("GCP auth refresh timed out after 3 minutes. Run your auth command manually in a separate terminal."):r.red("Error running gcpAuthRefresh (in settings or ~/.context.json):");console.error(e),n.endAuthentication(!1),o(!1)}})})}export const refreshGcpCredentialsIfNeeded=Z(async()=>await async function(){const r=getConfiguredGcpAuthRefresh();if(!r)return!1;if(isGcpAuthRefreshFromProjectSettings()&&!G()&&!m()){const r=new Error(`Security: gcpAuthRefresh executed before workspace trust is confirmed. If you see this message, post in ${e.FEEDBACK_CHANNEL}.`);return M("gcpAuthRefresh invoked before trust check",r),a("tengu_gcpAuthRefresh_missing_trust",{}),!1}try{if(Y("Checking GCP credentials validity for auth refresh"),await checkGcpCredentialsValid())return Y("GCP credentials are valid, skipping auth refresh command"),!1}catch{}return refreshGcpAuth(r)}(),36e5);export function clearGcpCredentialsCache(){refreshGcpCredentialsIfNeeded.cache.clear()}export function prefetchGcpCredentialsIfSafe(){if(getConfiguredGcpAuthRefresh()){if(isGcpAuthRefreshFromProjectSettings()){if(!G()&&!m())return}refreshGcpCredentialsIfNeeded()}}export function prefetchAwsCredentialsAndBedRockInfoIfSafe(){const e=getConfiguredAwsAuthRefresh(),r=getConfiguredAwsCredentialExport();if(e||r){if(isAwsAuthRefreshFromProjectSettings()||isAwsCredentialExportFromProjectSettings()){if(!G()&&!m())return}refreshAndGetAwsCredentials(),d()}}export const getApiKeyFromConfigOrMacOSKeychain=i(()=>{if("darwin"===process.platform){const e=re();if(e){if(e.stdout)return{key:e.stdout,source:"/login managed key"}}else{const e=ne();try{const r=q(`security find-generic-password -a $USER -w -s "${e}"`);if(r)return{key:r,source:"/login managed key"}}catch(e){J(e)}}}const e=j();return e.primaryApiKey?{key:e.primaryApiKey,source:"/login managed key"}:null});function isValidApiKey(e){return/^[a-zA-Z0-9-_\.]+$/.test(e)}function getStoredProviderApiKey(e,r){try{const t=Q().read();if(r){const n=t?.providerProfileApiKeys?.[r];if("string"==typeof n&&n.trim())return n;if(!O(e,r))return null}return t?.providerApiKeys?.[e]??null}catch{return null}}export function hasStoredProviderApiKey(e,r){return Boolean(getStoredProviderApiKey(e,r))}export async function saveProviderApiKey(e,r){if(!isValidApiKey(r))throw new Error("Formato de clave API inválido. La clave API solo debe contener caracteres alfanuméricos, guiones, guiones bajos y puntos.");const t=Q(),n=t.read()||{},o=E(e)?T(e,{createIfMissing:!0})?.id??null:null;if(!t.update({...n,providerApiKeys:{...n.providerApiKeys??{},[e]:r},...o?{providerProfileApiKeys:{...n.providerProfileApiKeys??{},[o]:r}}:{}}).success)throw new Error(`Failed to save ${e} API key`)}export async function removeProviderApiKey(e){const r=Q(),t=r.read()||{},n={...t.providerApiKeys??{}};delete n[e];const o={...t.providerProfileApiKeys??{}};if(E(e)){const r=_(e);r&&delete o[r]}if(!r.update({...t,providerApiKeys:n,providerProfileApiKeys:o}).success)throw new Error(`Failed to remove ${e} API key`)}export async function saveApiKey(e){if(!isValidApiKey(e))throw new Error("Formato de clave API inválido. La clave API solo debe contener caracteres alfanuméricos, guiones, guiones bajos y puntos.");await maybeRemoveApiKeyFromMacOSKeychain();let r=!1;if("darwin"===process.platform)try{const t=ne(),o=oe(),s=`add-generic-password -U -a "${o}" -s "${t}" -X "${Buffer.from(e,"utf-8").toString("hex")}"\n`;await n("security",["-i"],{input:s,reject:!1}),a("tengu_api_key_saved_to_keychain",{}),r=!0}catch(e){J(e),a("tengu_api_key_keychain_error",{error:W(e)}),a("tengu_api_key_saved_to_config",{})}else a("tengu_api_key_saved_to_config",{});const t=R(e);F(n=>{const o=n.customApiKeyResponses?.approved??[];return{...n,primaryApiKey:r?n.primaryApiKey:e,customApiKeyResponses:{...n.customApiKeyResponses,approved:o.includes(t)?o:[...o,t],rejected:n.customApiKeyResponses?.rejected??[]}}}),getApiKeyFromConfigOrMacOSKeychain.cache.clear?.(),ee()}export function isCustomApiKeyApproved(e){const r=j(),t=R(e);return r.customApiKeyResponses?.approved?.includes(t)??!1}export async function removeApiKey(){await maybeRemoveApiKeyFromMacOSKeychain(),F(e=>({...e,primaryApiKey:void 0})),getApiKeyFromConfigOrMacOSKeychain.cache.clear?.(),ee()}async function maybeRemoveApiKeyFromMacOSKeychain(){try{await N()}catch(e){J(e)}}export function saveOAuthTokensIfNeeded(e,r){if(!S(e.scopes))return a("tengu_oauth_tokens_not_claude_ai",{}),{success:!0};if(!e.refreshToken||!e.expiresAt)return a("tengu_oauth_tokens_inference_only",{}),{success:!0};const t=Q(),n=t.name;try{const o=t.read()||{},s=o.claudeAiOauth,i=r??_("claude"),c={accessToken:e.accessToken,refreshToken:e.refreshToken,expiresAt:e.expiresAt,scopes:e.scopes,subscriptionType:e.subscriptionType??s?.subscriptionType??null,rateLimitTier:e.rateLimitTier??s?.rateLimitTier??null};i&&(o.providerProfileOauth={...o.providerProfileOauth??{},[i]:c});const u=t.update(o);return u.success?a("tengu_oauth_tokens_saved",{storageBackend:n}):a("tengu_oauth_tokens_save_failed",{storageBackend:n}),getClaudeAIOAuthTokens.cache?.clear?.(),L(),le(),u}catch(e){return J(e),a("tengu_oauth_tokens_save_exception",{storageBackend:n,error:W(e)}),{success:!1,warning:"Failed to save OAuth tokens"}}}export function saveOpenAIOAuthTokens(e,r){const t=Q(),n=t.name;try{const o=t.read()||{},s=r??_("openai"),i={accessToken:e.accessToken,refreshToken:e.refreshToken,expiresAt:e.expiresAt,scopes:e.scopes,subscriptionType:e.subscriptionType??null,rateLimitTier:e.rateLimitTier??null};o.openAiOauth=i,s&&(o.providerProfileOauth={...o.providerProfileOauth??{},[s]:i});const c=t.update(o);return c.success?a("tengu_openai_oauth_tokens_saved",{storageBackend:n}):a("tengu_openai_oauth_tokens_save_failed",{storageBackend:n}),getOpenAIOAuthTokens.cache?.clear?.(),L(),le(),c}catch(e){return J(e),a("tengu_openai_oauth_tokens_save_exception",{storageBackend:n,error:W(e)}),{success:!1,warning:"Failed to save OpenAI OAuth tokens"}}}export function getClaudeAIOAuthTokens(){if(X())return null;const e=process.env.CONTEXT_CODE_OAUTH_TOKEN??process.env.CLAUDE_CODE_OAUTH_TOKEN;if(isManagedOAuthContext()&&e)return{accessToken:e,refreshToken:null,expiresAt:null,scopes:["user:inference"],subscriptionType:null,rateLimitTier:null};const r=isManagedOAuthContext()?w():null;if(r)return{accessToken:r,refreshToken:null,expiresAt:null,scopes:["user:inference"],subscriptionType:null,rateLimitTier:null};try{const e=getStoredProviderOAuthTokens("claude",_("claude"));return e?.accessToken?e:null}catch(e){return J(e),null}}export function getOpenAIOAuthTokens(){if(X())return null;if(process.env.OPENAI_OAUTH_TOKEN)return{accessToken:process.env.OPENAI_OAUTH_TOKEN,refreshToken:null,expiresAt:null,scopes:["responses:inference"],subscriptionType:null,rateLimitTier:null};try{const e=getStoredProviderOAuthTokens("openai",_("openai"));return e?.accessToken?e:null}catch(e){return J(e),null}}export function getOpenAIAccessToken(){return process.env.OPENAI_API_KEY||process.env.OPENAI_API_TOKEN||getStoredProviderApiKey("openai",_("openai"))||getOpenAIOAuthTokens()?.accessToken||null}export function getOpenRouterAccessToken(){return process.env.OPENROUTER_API_KEY||process.env.OPENROUTER_API_TOKEN||getStoredProviderApiKey("openrouter",_("openrouter"))||null}export async function checkGeminiGoogleCredentialsValid(){try{const e=await getGeminiGoogleAuthHeaders(),r=process.env.GEMINI_GOOGLE_PROJECT_ID?.trim()||void 0,t=fetch("https://cloudcode-pa.googleapis.com/v1internal:loadCodeAssist",{method:"POST",headers:e,body:JSON.stringify({cloudaicompanionProject:r,metadata:{ideType:"IDE_UNSPECIFIED",platform:"PLATFORM_UNSPECIFIED",pluginType:"GEMINI",duetProject:r},mode:"HEALTH_CHECK"})}).then(e=>{if(!e.ok)throw new Error(`Gemini credentials check failed: ${e.status}`)}),n=ue(5e3).then(()=>{throw new GcpCredentialsTimeoutError("Gemini credentials check timed out")});return await Promise.race([t,n]),!0}catch{return!1}}export function getGeminiGoogleOAuthTokens(){try{const e=_("gemini-google"),r=Q().read(),t=e?r?.providerProfileOauth?.[e]:null;if(t?.accessToken)return t;const n=Object.entries(r?.providerProfileOauth??{}).find(([e,r])=>e.startsWith("gemini-google/")&&"object"==typeof r&&null!==r&&"string"==typeof r.accessToken&&r.accessToken.trim())?.[1];return n?.accessToken?n:null}catch{return null}}export function saveGeminiGoogleOAuthTokens(e){const r=Q(),t=r.name;try{const n=r.read()||{},o=_("gemini-google")??g("gemini-google").id,s={accessToken:e.accessToken,refreshToken:e.refreshToken,expiresAt:e.expiresAt,scopes:e.scopes,subscriptionType:null,rateLimitTier:null,projectId:e.projectId};o&&(n.providerProfileOauth={...n.providerProfileOauth??{},[o]:s});const i=r.update(n);return a(i.success?"tengu_gemini_google_oauth_tokens_saved":"tengu_gemini_google_oauth_tokens_save_failed",{storageBackend:t}),i}catch(e){return J(e),a("tengu_gemini_google_oauth_tokens_save_exception",{storageBackend:t,error:W(e)}),{success:!1,warning:"Failed to save Gemini OAuth tokens"}}}function quoteShellArg(e){return`"${e.replace(/"/g,'\\"')}"`}export function getGeminiGoogleAuthCommand(){const e=process.env.GEMINI_OAUTH_CLIENT_SECRET_FILE||process.env.GOOGLE_OAUTH_CLIENT_SECRET_FILE,r=ge.join(",");return`gcloud auth application-default login${e?` --client-id-file=${quoteShellArg(e)}`:""} --scopes=${quoteShellArg(r)}`}export async function refreshGeminiGoogleAuth(){return refreshGcpAuth(getGeminiGoogleAuthCommand())}export function getGeminiApiAccessToken(){return process.env.GEMINI_API_KEY||process.env.GOOGLE_API_KEY||getStoredProviderApiKey("gemini-api",_("gemini-api"))||null}export async function getGeminiGoogleAuthHeaders(){const e=process.env.GEMINI_OAUTH_TOKEN||process.env.GOOGLE_OAUTH_ACCESS_TOKEN,r={"Content-Type":"application/json"};if(e)r.Authorization=`Bearer ${e}`;else{const e=await async function(){const e=getGeminiGoogleOAuthTokens();if(!e?.refreshToken)return e;if(e.expiresAt&&e.expiresAt>Date.now()+6e4)return e;const r=await fetch(A,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:new URLSearchParams({grant_type:"refresh_token",refresh_token:e.refreshToken,client_id:u,client_secret:p})});if(!r.ok)return e;const t=await r.json(),n={...e,accessToken:t.access_token,expiresAt:t.expires_in?Date.now()+1e3*t.expires_in:e.expiresAt,scopes:t.scope?.split(/\s+/).filter(Boolean)??e.scopes};return saveGeminiGoogleOAuthTokens(n),n}();if(e?.accessToken){r.Authorization=`Bearer ${e.accessToken}`;const t=process.env.GEMINI_GOOGLE_PROJECT_ID?.trim();t&&(r["x-goog-user-project"]=t)}else{const{GoogleAuth:e}=await import("google-auth-library"),t=new e({scopes:ge}),n=await t.getClient(),o=await n.getRequestHeaders();if("function"==typeof o.forEach)o.forEach((e,t)=>{r[t]=e});else for(const[e,t]of Object.entries(o))Array.isArray(t)?r[e]=t.map(String).join(", "):null!=t&&(r[e]=String(t))}}const t=process.env.GEMINI_GOOGLE_PROJECT_ID?.trim()||void 0;return t&&(r["x-goog-user-project"]=t),r}export function getZAIAccessToken(){return process.env.ZAI_API_KEY||getStoredProviderApiKey("zai",_("zai"))||null}export function getMiniMaxAccessToken(){return process.env.MINIMAX_API_KEY||getStoredProviderApiKey("minimax",_("minimax"))||null}export function getNvidiaAccessToken(){return process.env.NVIDIA_API_KEY||getStoredProviderApiKey("nvidia",_("nvidia"))||null}export function getDeepSeekAccessToken(){return process.env.DEEPSEEK_API_KEY||getStoredProviderApiKey("deepseek",_("deepseek"))||null}export function getXaiAccessToken(){return process.env.XAI_API_KEY||getStoredProviderApiKey("xai",_("xai"))||null}export function getOllamaAccessToken(){return"ollama"}export function getOllamaCloudAccessToken(){return process.env.OLLAMA_API_KEY||getStoredProviderApiKey("ollama-cloud",_("ollama-cloud"))||null}export function getOpenAICompatibleAccessToken(e=f()){switch(e){case"openrouter":return getOpenRouterAccessToken();case"gemini-api":return getGeminiApiAccessToken();case"gemini-google":return process.env.GEMINI_OAUTH_TOKEN||process.env.GOOGLE_OAUTH_ACCESS_TOKEN||null;case"zai":return getZAIAccessToken();case"minimax":return getMiniMaxAccessToken();case"nvidia":return getNvidiaAccessToken();case"deepseek":return getDeepSeekAccessToken();case"xai":return getXaiAccessToken();case"gmi":case"novita":case"stepfun":case"huggingface":case"opencode-zen":case"arcee":case"alibaba":case"kimi":{const r=Ae[e];return(r?process.env[r]:void 0)||getStoredProviderApiKey(e,_(e))||null}case"ollama":return getOllamaAccessToken();case"ollama-cloud":return getOllamaCloudAccessToken();case"custom-openai":return process.env.CUSTOM_OPENAI_API_KEY||getStoredProviderApiKey("custom-openai",_("custom-openai"))||null;case"custom-anthropic":return process.env.CUSTOM_ANTHROPIC_API_KEY||getStoredProviderApiKey("custom-anthropic",_("custom-anthropic"))||null;default:return getOpenAIAccessToken()}}export async function getOpenAIOAuthTokensAsync(){if(X())return null;if(process.env.OPENAI_OAUTH_TOKEN)return getOpenAIOAuthTokens();try{const e=Q(),r=await e.readAsync(),t=_("openai"),n=t&&r?.providerProfileOauth?.[t]||(t&&!O("openai",t)?null:r?.openAiOauth);return n?.accessToken?n:null}catch(e){return J(e),null}}export function clearOAuthTokenCache(){getClaudeAIOAuthTokens.cache?.clear?.(),getOpenAIOAuthTokens.cache?.clear?.(),te()}let Ee=0;async function invalidateOAuthCacheIfDiskChanged(){try{const e="sqlite"===Q().name?ie():se(),{mtimeMs:r}=await s(e);r!==Ee&&(Ee=r,clearOAuthTokenCache())}catch{getClaudeAIOAuthTokens.cache?.clear?.(),getOpenAIOAuthTokens.cache?.clear?.()}}const Te=new Map;export function handleOAuth401Error(e){const r=Te.get(e);if(r)return r;const t=async function(e){clearOAuthTokenCache();const r=await getClaudeAIOAuthTokensAsync();if(!r?.refreshToken)return!1;if(r.accessToken!==e)return a("tengu_oauth_401_recovered_from_keychain",{}),!0;return checkAndRefreshOAuthTokenIfNeeded(0,!0)}(e).finally(()=>{Te.delete(e)});return Te.set(e,t),t}export async function handleOpenAIOAuth401Error(e){clearOAuthTokenCache();const r=await getOpenAIOAuthTokensAsync();return!!r?.refreshToken&&(r.accessToken!==e?(a("tengu_openai_oauth_401_recovered_from_keychain",{}),!0):checkAndRefreshOpenAIOAuthTokenIfNeeded(0,!0))}export async function getClaudeAIOAuthTokensAsync(){if(X())return null;if(isManagedOAuthContext()&&(process.env.CONTEXT_CODE_OAUTH_TOKEN||process.env.CLAUDE_CODE_OAUTH_TOKEN||w()))return getClaudeAIOAuthTokens();try{const e=Q(),r=await e.readAsync(),t=_("claude"),n=t&&r?.providerProfileOauth?.[t]||(t&&!O("claude",t)?null:r?.claudeAiOauth);return n?.accessToken?n:null}catch(e){return J(e),null}}let me=null,ye=null;export function checkAndRefreshOAuthTokenIfNeeded(e=0,r=!1){if(0===e&&!r){if(me)return me;const t=checkAndRefreshOAuthTokenIfNeededImpl(e,r);return me=t.finally(()=>{me=null}),me}return checkAndRefreshOAuthTokenIfNeededImpl(e,r)}export function checkAndRefreshOpenAIOAuthTokenIfNeeded(e=0,r=!1){if(0===e&&!r){if(ye)return ye;const t=checkAndRefreshOpenAIOAuthTokenIfNeededImpl(e,r);return ye=t.finally(()=>{ye=null}),ye}return checkAndRefreshOpenAIOAuthTokenIfNeededImpl(e,r)}async function checkAndRefreshOAuthTokenIfNeededImpl(e,r){await invalidateOAuthCacheIfDiskChanged();const t=getClaudeAIOAuthTokens();if(!(r||t?.refreshToken&&v(t.expiresAt)))return!1;if(!t?.refreshToken)return!1;if(!S(t.scopes))return!1;getClaudeAIOAuthTokens.cache?.clear?.(),te();const n=await getClaudeAIOAuthTokensAsync();if(!n?.refreshToken||!v(n.expiresAt))return!1;const s=$();let i;await o(s,{recursive:!0});try{a("tengu_oauth_token_refresh_lock_acquiring",{}),i=await V.lock(s),a("tengu_oauth_token_refresh_lock_acquired",{})}catch(t){return"ELOCKED"===t.code?e<5?(a("tengu_oauth_token_refresh_lock_retry",{retryCount:e+1}),await ue(1e3+1e3*Math.random()),checkAndRefreshOAuthTokenIfNeededImpl(e+1,r)):(a("tengu_oauth_token_refresh_lock_retry_limit_reached",{maxRetries:5}),!1):(J(t),a("tengu_oauth_token_refresh_lock_error",{error:W(t)}),!1)}try{getClaudeAIOAuthTokens.cache?.clear?.(),te();const e=await getClaudeAIOAuthTokensAsync();if(!e?.refreshToken||!v(e.expiresAt))return a("tengu_oauth_token_refresh_race_resolved",{}),!1;a("tengu_oauth_token_refresh_starting",{});return saveOAuthTokensIfNeeded(await K(e.refreshToken,{scopes:S(e.scopes)?void 0:e.scopes})),getClaudeAIOAuthTokens.cache?.clear?.(),te(),!0}catch(e){J(e),getClaudeAIOAuthTokens.cache?.clear?.(),te();const r=await getClaudeAIOAuthTokensAsync();return!(!r||v(r.expiresAt))&&(a("tengu_oauth_token_refresh_race_recovered",{}),!0)}finally{a("tengu_oauth_token_refresh_lock_releasing",{}),await i(),a("tengu_oauth_token_refresh_lock_released",{})}}async function checkAndRefreshOpenAIOAuthTokenIfNeededImpl(e,r){await invalidateOAuthCacheIfDiskChanged();const t=getOpenAIOAuthTokens();if(!(r||t?.refreshToken&&v(t.expiresAt)))return!1;if(!t?.refreshToken)return!1;getOpenAIOAuthTokens.cache?.clear?.(),te();const n=await getOpenAIOAuthTokensAsync();if(!n?.refreshToken||!v(n.expiresAt))return!1;const s=$();let i;await o(s,{recursive:!0});try{a("tengu_openai_oauth_token_refresh_lock_acquiring",{}),i=await V.lock(s),a("tengu_openai_oauth_token_refresh_lock_acquired",{})}catch(t){return"ELOCKED"===t.code?e<5?(a("tengu_openai_oauth_token_refresh_lock_retry",{retryCount:e+1}),await ue(1e3+1e3*Math.random()),checkAndRefreshOpenAIOAuthTokenIfNeededImpl(e+1,r)):(a("tengu_openai_oauth_token_refresh_lock_retry_limit_reached",{maxRetries:5}),!1):(J(t),!1)}try{getOpenAIOAuthTokens.cache?.clear?.(),te();const e=await getOpenAIOAuthTokensAsync();if(!e?.refreshToken||!v(e.expiresAt))return a("tengu_openai_oauth_token_refresh_race_resolved",{}),!1;a("tengu_openai_oauth_token_refresh_starting",{});return saveOpenAIOAuthTokens(await I(e.refreshToken,{scopes:e.scopes})),getOpenAIOAuthTokens.cache?.clear?.(),te(),!0}catch(e){J(e),getOpenAIOAuthTokens.cache?.clear?.(),te();const r=await getOpenAIOAuthTokensAsync();return!(!r||v(r.expiresAt))&&(a("tengu_openai_oauth_token_refresh_race_recovered",{}),!0)}finally{a("tengu_openai_oauth_token_refresh_lock_releasing",{}),await i(),a("tengu_openai_oauth_token_refresh_lock_released",{})}}export function isClaudeAISubscriber(){return!!isAnthropicAuthEnabled()&&S(getClaudeAIOAuthTokens()?.scopes)}export function hasProfileScope(){return getClaudeAIOAuthTokens()?.scopes?.includes(c)??!1}export function is1PApiCustomer(){return!(B(process.env.CONTEXT_CODE_USE_BEDROCK)||B(process.env.CLAUDE_CODE_USE_BEDROCK)||B(process.env.CONTEXT_CODE_USE_VERTEX)||B(process.env.CLAUDE_CODE_USE_VERTEX)||B(process.env.CONTEXT_CODE_USE_FOUNDRY)||B(process.env.CLAUDE_CODE_USE_FOUNDRY)||h(f()))&&!isClaudeAISubscriber()}export function getOauthAccountInfo(){return isAnthropicAuthEnabled()?j().oauthAccount:void 0}export function isOverageProvisioningAllowed(){const e=getOauthAccountInfo(),r=e?.billingType;return!(!isClaudeAISubscriber()||!r)&&("stripe_subscription"===r||"stripe_subscription_contracted"===r||"apple_subscription"===r||"google_play_subscription"===r)}export function hasOpusAccess(){const e=getSubscriptionType();return"max"===e||"enterprise"===e||"team"===e||"pro"===e||null===e}export function getSubscriptionType(){if(C())return k();if(!isAnthropicAuthEnabled())return null;const e=getClaudeAIOAuthTokens();return e?e.subscriptionType??null:null}export function isMaxSubscriber(){return"max"===getSubscriptionType()}export function isTeamSubscriber(){return"team"===getSubscriptionType()}export function isTeamPremiumSubscriber(){return"team"===getSubscriptionType()&&"default_claude_max_5x"===getRateLimitTier()}export function isEnterpriseSubscriber(){return"enterprise"===getSubscriptionType()}export function isProSubscriber(){return"pro"===getSubscriptionType()}export function getRateLimitTier(){if(!isAnthropicAuthEnabled())return null;const e=getClaudeAIOAuthTokens();return e?e.rateLimitTier??null:null}export function getSubscriptionName(){switch(getSubscriptionType()){case"enterprise":return"Context Empresarial";case"team":return"Context Equipo";case"max":return"Context Max";case"pro":return"Context Pro";default:return"Context API"}}export function isUsing3PServices(){return!!(B(process.env.CONTEXT_CODE_USE_BEDROCK)||B(process.env.CLAUDE_CODE_USE_BEDROCK)||B(process.env.CONTEXT_CODE_USE_VERTEX)||B(process.env.CLAUDE_CODE_USE_VERTEX)||B(process.env.CONTEXT_CODE_USE_FOUNDRY)||B(process.env.CLAUDE_CODE_USE_FOUNDRY)||h(f()))}function getConfiguredOtelHeadersHelper(){return(ce()||{}).otelHeadersHelper}export function isOtelHeadersHelperFromProjectOrLocalSettings(){const e=getConfiguredOtelHeadersHelper();if(!e)return!1;const r=ae("projectSettings"),t=ae("localSettings");return r?.otelHeadersHelper===e||t?.otelHeadersHelper===e}let ke=null,Ce=0;const ve=174e4;export function getOtelHeadersFromHelper(){const e=getConfiguredOtelHeadersHelper();if(!e)return{};const r=parseInt(process.env.CONTEXT_CODE_OTEL_HEADERS_HELPER_DEBOUNCE_MS||process.env.CLAUDE_CODE_OTEL_HEADERS_HELPER_DEBOUNCE_MS||ve.toString());if(ke&&Date.now()-Ce<r)return ke;if(isOtelHeadersHelperFromProjectOrLocalSettings()){if(!G())return{}}try{const r=q(e,{timeout:3e4})?.toString().trim();if(!r)throw new Error("otelHeadersHelper did not return a valid value");const t=pe(r);if("object"!=typeof t||null===t||Array.isArray(t))throw new Error("otelHeadersHelper must return a JSON object with string key-value pairs");for(const[e,r]of Object.entries(t))if("string"!=typeof r)throw new Error(`otelHeadersHelper returned non-string value for key "${e}": ${typeof r}`);return ke=t,Ce=Date.now(),ke}catch(e){throw J(new Error(`Error getting OpenTelemetry headers from otelHeadersHelper (in settings): ${W(e)}`)),e}}export function isConsumerSubscriber(){const e=getSubscriptionType();return isClaudeAISubscriber()&&null!==e&&("max"===(r=e)||"pro"===r);var r}export function getAccountInformation(){if("firstParty"!==f())return;const{source:e}=getAuthTokenSource(),r={};"CLAUDE_CODE_OAUTH_TOKEN"===e||"CLAUDE_CODE_OAUTH_TOKEN_FILE_DESCRIPTOR"===e?r.tokenSource=e:isClaudeAISubscriber()?r.subscription=getSubscriptionName():r.tokenSource=e;const{key:t,source:n}=getAnthropicApiKeyWithSource();if(t&&(r.apiKeySource=n),"claude.ai"===e||"/login managed key"===n){const e=getOauthAccountInfo()?.organizationName;e&&(r.organization=e)}const o=getOauthAccountInfo()?.emailAddress;return"claude.ai"!==e&&"/login managed key"!==n||!o||(r.email=o),r}export async function validateForceLoginOrg(){if(process.env.ANTHROPIC_UNIX_SOCKET)return{valid:!0};if(!isAnthropicAuthEnabled())return{valid:!0};const e=ae("policySettings")?.forceLoginOrgUUID;if(!e)return{valid:!0};await checkAndRefreshOAuthTokenIfNeeded();const r=getClaudeAIOAuthTokens();if(!r)return{valid:!0};const{source:t}=getAuthTokenSource(),n="CLAUDE_CODE_OAUTH_TOKEN"===t||"CLAUDE_CODE_OAUTH_TOKEN_FILE_DESCRIPTOR"===t,o=await P(r.accessToken);if(!o)return{valid:!1,message:`Unable to verify organization for the current authentication token.\nThis machine requires organization ${e} but the profile could not be fetched.\nThis may be a network error, or the token may lack the user:profile scope required for\nverification (tokens from 'context setup-token' do not include this scope).\nTry again, or obtain a full-scope token via 'context auth login'.`};const s=o.organization.uuid;if(s===e)return{valid:!0};if(n){return{valid:!1,message:`The ${"CLAUDE_CODE_OAUTH_TOKEN"===t?"CLAUDE_CODE_OAUTH_TOKEN":"CLAUDE_CODE_OAUTH_TOKEN_FILE_DESCRIPTOR"} environment variable provides a token for a\ndifferent organization than required by this machine's managed settings.\n\nRequired organization: ${e}\nToken organization: ${s}\n\nRemove the environment variable or obtain a token for the correct organization.`}}return{valid:!1,message:`Your authentication token belongs to organization ${s},\nbut this machine requires organization ${e}.\n\nPlease log in with the correct organization: context auth login`}}class GcpCredentialsTimeoutError extends Error{}
@@ -1 +1 @@
1
- import{chmod as e,mkdir as o,readFile as t,writeFile as n}from"fs/promises";import{homedir as r}from"os";import{join as i}from"path";import{fileURLToPath as s}from"url";import{getIsInteractive as a,getIsNonInteractiveSession as c,getSessionBypassPermissionsMode as m}from"../../bootstrap/state.js";import{isInBundledMode as l}from"../bundledMode.js";import{getGlobalConfig as d,saveGlobalConfig as p}from"../config.js";import{logForDebugging as h}from"../debug.js";import{getClaudeConfigHomeDir as C,isEnvDefinedFalsy as f,isEnvTruthy as u}from"../envUtils.js";import{execFileNoThrowWithCwd as E}from"../execFileNoThrow.js";import{getPlatform as _}from"../platform.js";import{jsonStringify as x}from"../slowOperations.js";import{CLAUDE_IN_CHROME_MCP_SERVER_NAME as v,getAllBrowserDataPaths as g,getAllNativeMessagingHostsDirs as w,getAllWindowsRegistryKeys as b,openInChrome as $}from"./common.js";import{getChromeSystemPrompt as j}from"./prompt.js";import{isChromeExtensionInstalledPortable as y}from"./setupPortable.js";import{CONTEXT_BROWSER_TOOLS as A}from"./tools.js";let I;const D="com.contextcompany.browser_extension",N=`${D}.json`,O=process.env.CONTEXT_CODE_CHROME_EXTENSION_ID||"aonominmpekbkdilbgbgeijfoooamfho";export function shouldEnableClaudeInChrome(e){if(c()&&!0!==e)return!1;if(!0===e)return!0;if(!1===e)return!1;if(u(process.env.CONTEXT_CODE_ENABLE_CFC)||u(process.env.CLAUDE_CODE_ENABLE_CFC))return!0;if(f(process.env.CONTEXT_CODE_ENABLE_CFC)||f(process.env.CLAUDE_CODE_ENABLE_CFC))return!1;const o=d();return void 0!==o.claudeInChromeDefaultEnabled?o.claudeInChromeDefaultEnabled:a()&&isChromeExtensionInstalled_CACHED_MAY_BE_STALE()}let T;export function shouldAutoEnableClaudeInChrome(){return void 0!==T||(T=a()&&isChromeExtensionInstalled_CACHED_MAY_BE_STALE()),T}export function setupClaudeInChrome(){const e=l(),o=(I||(I=[...A]),I).map(e=>`mcp__${v}__${e.name}`),t={};m()&&(t.CLAUDE_CHROME_PERMISSION_MODE="skip_all_permission_checks");const n=Object.keys(t).length>0;if(e){return createWrapperScript(`"${process.execPath}" --chrome-native-host`).then(e=>installChromeNativeHostManifest(e)).catch(e=>h(`[Claude in Chrome] Failed to install native host: ${e}`,{level:"error"})),{mcpConfig:{[v]:{type:"stdio",command:process.execPath,args:["--claude-in-chrome-mcp"],scope:"dynamic",...n&&{env:t}}},allowedTools:o,systemPrompt:j()}}{const e=s(import.meta.url),r=i(e,".."),a=i(r,"..","..","entrypoints","cli.js");createWrapperScript(`"${process.execPath}" "${a}" --chrome-native-host`).then(e=>installChromeNativeHostManifest(e)).catch(e=>h(`[Claude in Chrome] Failed to install native host: ${e}`,{level:"error"}));return{mcpConfig:{[v]:{type:"stdio",command:process.execPath,args:[`${a}`,"--claude-in-chrome-mcp"],scope:"dynamic",...n&&{env:t}}},allowedTools:o,systemPrompt:j()}}}export async function installChromeNativeHostManifest(e){const s=function(){if("windows"===_()){const e=r(),o=process.env.APPDATA||i(e,"AppData","Local");return[i(o,"Context Code","ChromeNativeHost")]}return w().map(({path:e})=>e)}();if(0===s.length)throw Error("Claude in Chrome Native Host not supported on this platform");const a={name:D,description:"Context Code Browser Extension Native Host",path:e,type:"stdio",allowed_origins:[`chrome-extension://${O}/`,"chrome-extension://aonominmpekbkdilbgbgeijfoooamfho/","chrome-extension://my_context_code_extension_id/","chrome-extension://fcoeoabgfenejglbffodgkkbkcdhcgfn/",..."ant"===process.env.USER_TYPE?["chrome-extension://dihbgbndebgnbjfmelmegjepbnkhlgni/","chrome-extension://dngcpimnedloihjnnfngkgjoidhnaolf/"]:[]]},c=x(a,null,2);let m=!1;for(const e of s){const r=i(e,N);if(await t(r,"utf-8").catch(()=>null)!==c)try{await o(e,{recursive:!0}),await n(r,c),h(`[Claude in Chrome] Installed native host manifest at: ${r}`),m=!0}catch(e){h(`[Claude in Chrome] Failed to install manifest at ${r}: ${e}`)}}if("windows"===_()){!function(e){const o=b();for(const{browser:t,key:n}of o){const o=`${n}\\${D}`;E("reg",["add",o,"/ve","/t","REG_SZ","/d",e,"/f"]).then(e=>{0===e.code?h(`[Claude in Chrome] Registered native host for ${t} in Windows registry: ${o}`):h(`[Claude in Chrome] Failed to register native host for ${t} in Windows registry: ${e.stderr}`)})}}(i(s[0],N))}m&&isChromeExtensionInstalled().then(e=>{e?(h("[Claude in Chrome] First-time install detected, opening reconnect page in browser"),$("https://clau.de/chrome/reconnect")):h("[Claude in Chrome] First-time install detected, but extension not installed, skipping reconnect")})}async function createWrapperScript(r){const s=_(),a=i(C(),"chrome"),c=i(a,"windows"===s?"chrome-native-host.bat":"chrome-native-host"),m="windows"===s?`@echo off\nREM Chrome native host wrapper script\nREM Generated by Context Code - do not edit manually\n${r}\n`:`#!/bin/sh\n# Chrome native host wrapper script\n# Generated by Context Code - do not edit manually\nexec ${r}\n`;return await t(c,"utf-8").catch(()=>null)===m||(await o(a,{recursive:!0}),await n(c,m),"windows"!==s&&await e(c,493),h(`[Claude in Chrome] Created Chrome native host wrapper script: ${c}`)),c}function isChromeExtensionInstalled_CACHED_MAY_BE_STALE(){isChromeExtensionInstalled().then(e=>{if(!e)return;d().cachedChromeExtensionInstalled!==e&&p(o=>({...o,cachedChromeExtensionInstalled:e}))});return d().cachedChromeExtensionInstalled??!1}export async function isChromeExtensionInstalled(){const e=g();return 0===e.length?(h(`[Claude in Chrome] Unsupported platform for extension detection: ${_()}`),!1):y(e,h)}
1
+ import{chmod as e,mkdir as o,readFile as t,writeFile as n}from"fs/promises";import{homedir as r}from"os";import{join as i}from"path";import{fileURLToPath as s}from"url";import{getIsNonInteractiveSession as a,getSessionBypassPermissionsMode as c}from"../../bootstrap/state.js";import{isInBundledMode as m}from"../bundledMode.js";import{getGlobalConfig as l,saveGlobalConfig as p}from"../config.js";import{logForDebugging as d}from"../debug.js";import{getClaudeConfigHomeDir as h,isEnvDefinedFalsy as f,isEnvTruthy as C}from"../envUtils.js";import{execFileNoThrowWithCwd as u}from"../execFileNoThrow.js";import{getPlatform as E}from"../platform.js";import{jsonStringify as v}from"../slowOperations.js";import{CLAUDE_IN_CHROME_MCP_SERVER_NAME as _,getAllBrowserDataPaths as g,getAllNativeMessagingHostsDirs as w,getAllWindowsRegistryKeys as b,openInChrome as x}from"./common.js";import{getChromeSystemPrompt as $}from"./prompt.js";import{isChromeExtensionInstalledPortable as j}from"./setupPortable.js";import{CONTEXT_BROWSER_TOOLS as y}from"./tools.js";let N;const O="com.contextcompany.browser_extension",k=`${O}.json`,D=process.env.CONTEXT_CODE_CHROME_EXTENSION_ID||"aonominmpekbkdilbgbgeijfoooamfho";export function shouldEnableClaudeInChrome(e){if(a()&&!0!==e)return!1;if(!0===e)return!0;if(!1===e)return!1;if(C(process.env.CONTEXT_CODE_ENABLE_CFC)||C(process.env.CLAUDE_CODE_ENABLE_CFC))return!0;if(f(process.env.CONTEXT_CODE_ENABLE_CFC)||f(process.env.CLAUDE_CODE_ENABLE_CFC))return!1;const o=l();return void 0!==o.claudeInChromeDefaultEnabled&&o.claudeInChromeDefaultEnabled}export function shouldAutoEnableClaudeInChrome(){return!1}export function setupClaudeInChrome(){const e=m(),o=(N||(N=[...y]),N).map(e=>`mcp__${_}__${e.name}`),t={};c()&&(t.CLAUDE_CHROME_PERMISSION_MODE="skip_all_permission_checks");const n=Object.keys(t).length>0;if(e){return createWrapperScript(`"${process.execPath}" --chrome-native-host`).then(e=>installChromeNativeHostManifest(e)).catch(e=>d(`[Claude in Chrome] Failed to install native host: ${e}`,{level:"error"})),{mcpConfig:{[_]:{type:"stdio",command:process.execPath,args:["--claude-in-chrome-mcp"],scope:"dynamic",...n&&{env:t}}},allowedTools:o,systemPrompt:$()}}{const e=s(import.meta.url),r=i(e,".."),a=i(r,"..","..","entrypoints","cli.js");createWrapperScript(`"${process.execPath}" "${a}" --chrome-native-host`).then(e=>installChromeNativeHostManifest(e)).catch(e=>d(`[Claude in Chrome] Failed to install native host: ${e}`,{level:"error"}));return{mcpConfig:{[_]:{type:"stdio",command:process.execPath,args:[`${a}`,"--claude-in-chrome-mcp"],scope:"dynamic",...n&&{env:t}}},allowedTools:o,systemPrompt:$()}}}export async function installChromeNativeHostManifest(e){const s=function(){if("windows"===E()){const e=r(),o=process.env.APPDATA||i(e,"AppData","Local");return[i(o,"Context Code","ChromeNativeHost")]}return w().map(({path:e})=>e)}();if(0===s.length)throw Error("Claude in Chrome Native Host not supported on this platform");const a={name:O,description:"Context Code Browser Extension Native Host",path:e,type:"stdio",allowed_origins:[`chrome-extension://${D}/`,"chrome-extension://aonominmpekbkdilbgbgeijfoooamfho/","chrome-extension://my_context_code_extension_id/","chrome-extension://fcoeoabgfenejglbffodgkkbkcdhcgfn/",..."ant"===process.env.USER_TYPE?["chrome-extension://dihbgbndebgnbjfmelmegjepbnkhlgni/","chrome-extension://dngcpimnedloihjnnfngkgjoidhnaolf/"]:[]]},c=v(a,null,2);let m=!1;for(const e of s){const r=i(e,k);if(await t(r,"utf-8").catch(()=>null)!==c)try{await o(e,{recursive:!0}),await n(r,c),d(`[Claude in Chrome] Installed native host manifest at: ${r}`),m=!0}catch(e){d(`[Claude in Chrome] Failed to install manifest at ${r}: ${e}`)}}if("windows"===E()){!function(e){const o=b();for(const{browser:t,key:n}of o){const o=`${n}\\${O}`;u("reg",["add",o,"/ve","/t","REG_SZ","/d",e,"/f"]).then(e=>{0===e.code?d(`[Claude in Chrome] Registered native host for ${t} in Windows registry: ${o}`):d(`[Claude in Chrome] Failed to register native host for ${t} in Windows registry: ${e.stderr}`)})}}(i(s[0],k))}m&&isChromeExtensionInstalled().then(e=>{e?(d("[Claude in Chrome] First-time install detected, opening reconnect page in browser"),x("https://clau.de/chrome/reconnect")):d("[Claude in Chrome] First-time install detected, but extension not installed, skipping reconnect")})}async function createWrapperScript(r){const s=E(),a=i(h(),"chrome"),c=i(a,"windows"===s?"chrome-native-host.bat":"chrome-native-host"),m="windows"===s?`@echo off\nREM Chrome native host wrapper script\nREM Generated by Context Code - do not edit manually\n${r}\n`:`#!/bin/sh\n# Chrome native host wrapper script\n# Generated by Context Code - do not edit manually\nexec ${r}\n`;return await t(c,"utf-8").catch(()=>null)===m||(await o(a,{recursive:!0}),await n(c,m),"windows"!==s&&await e(c,493),d(`[Claude in Chrome] Created Chrome native host wrapper script: ${c}`)),c}export async function isChromeExtensionInstalled(){const e=g();return 0===e.length?(d(`[Claude in Chrome] Unsupported platform for extension detection: ${E()}`),!1):j(e,d)}