@iaforged/context-code 2.0.9 → 2.1.0

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.
@@ -1 +1 @@
1
- import{jsxs as e,jsx as o,Fragment as r}from"react/jsx-runtime";import{c as t}from"react/compiler-runtime";import{useCallback as i,useEffect as n,useRef as a,useState as s}from"react";import{logEvent as l}from"../services/analytics/index.js";import{installOAuthTokens as c}from"../cli/handlers/auth.js";import{useTerminalSize as d}from"../hooks/useTerminalSize.js";import{setClipboard as u}from"../ink/termio/osc.js";import{useTerminalNotification as m}from"../ink/useTerminalNotification.js";import{Box as p,Link as h,Text as g}from"../ink.js";import{useKeybinding as f}from"../keybindings/useKeybinding.js";import{getSSLErrorHint as _}from"../services/api/errorUtils.js";import{sendNotification as v}from"../services/notifier.js";import{OAuthService as y}from"../services/oauth/index.js";import{getOAuthRequestDetails as C}from"../services/oauth/client.js";import{checkGeminiGoogleCredentialsValid as A,getOauthAccountInfo as b,saveGeminiGoogleOAuthTokens as x,saveProviderApiKey as k,validateForceLoginOrg as O}from"../utils/auth.js";import{startGeminiCliOAuthFlow as P}from"../services/oauth/geminiCli.js";import{resolveProviderProfile as I}from"../utils/model/providerProfiles.js";import{logError as S}from"../utils/log.js";import{getVisibleProvider as D}from"../utils/model/providerCatalog.js";import{getConfiguredProviderBaseUrl as T,setProviderBaseUrl as w}from"../utils/model/providerBaseUrls.js";import{getSettings_DEPRECATED as j}from"../utils/settings/settings.js";import{Select as M}from"./CustomSelect/select.js";import{KeyboardShortcutHint as U}from"./design-system/KeyboardShortcutHint.js";import{Spinner as R}from"./Spinner.js";import G from"./TextInput.js";const E=["deepseek","minimax","openrouter","zai","nvidia","ollama","openai","claudeai","gemini-google","gemini-api","console"];function sortLoginProviderOptions(e){const o=new Map(E.map((e,o)=>[e,o]));return[...e].sort((e,r)=>(o.get(e.value)??Number.MAX_SAFE_INTEGER)-(o.get(r.value)??Number.MAX_SAFE_INTEGER))}const B="Pega aqui el codigo si se solicita > ";function formatOAuthDebugDetails(e,o){if("openai"!==e)return"";const r=C({provider:e,port:o,isManual:!1});return[`authorize=${r.authorizeUrl}`,`redirect_uri=${r.redirectUri}`,`scope=${r.scopes.join(" ")}`].join("\n")}export function ConsoleOAuthFlow({onDone:r,startingMessage:t,mode:C="login",forceLoginMethod:b,profileName:T}){const M=j()||{},R=b??M.forceLoginMethod,G=M.forceLoginOrgUUID,E="claudeai"===R?"Método de acceso preseleccionado: Plan de suscripción (Context Pro/Max)":"console"===R?"Método de acceso preseleccionado: Facturación por uso de API (Anthropic Console)":"openai"===R?"Método de acceso preseleccionado: OpenAI / Codex OAuth":null,B=m(),[L,z]=s(()=>"setup-token"===C||"claudeai"===R||"console"===R||"openai"===R?{state:"ready_to_start"}:{state:"idle"}),[K,N]=s(""),[F,$]=s(0),[W]=s(()=>new y),[V,X]=s(()=>"openai"===R?"openai":"anthropic"),[Y,q]=s(()=>"setup-token"===C||"claudeai"===R),[H,Z]=s(!1),[J,Q]=s(!1),ee=d().columns-37-1,[oe,re]=s(""),[te,ie]=s(0),[ne,ae]=s(""),[se,le]=s(0);n(()=>{"claudeai"===R?l("tengu_oauth_claudeai_forced",{}):"console"===R&&l("tengu_oauth_console_forced",{})},[R]),n(()=>{if("about_to_retry"===L.state){const e=setTimeout(z,1e3,L.nextState);return()=>clearTimeout(e)}},[L]),f("confirm:yes",()=>{l("tengu_oauth_success",{loginWithClaudeAi:Y}),r(V)},{context:"Confirmation",isActive:"success"===L.state&&"setup-token"!==C}),n(()=>{if("success"===L.state&&!process.stdin.isTTY){const e=setTimeout(()=>{l("tengu_oauth_success",{loginWithClaudeAi:Y}),r(V)},800);return()=>clearTimeout(e)}},[L.state,V,Y,r]),f("confirm:yes",()=>{z({state:"idle"})},{context:"Confirmation",isActive:"platform_setup"===L.state}),f("confirm:yes",()=>{ue()},{context:"Confirmation",isActive:"provider_google_setup"===L.state}),f("confirm:yes",()=>{"error"===L.state&&L.toRetry&&(N(""),z({state:"about_to_retry",nextState:L.toRetry}))},{context:"Confirmation",isActive:"error"===L.state&&!!L.toRetry}),f("cancel",()=>{z({state:"idle"})},{context:"Confirmation",isActive:"provider_api_key_input"===L.state||"provider_local_setup"===L.state||"provider_google_setup"===L.state||"error"===L.state}),n(()=>{"c"===K&&"waiting_for_login"===L.state&&H&&!J&&(u(L.url).then(e=>{e&&process.stdout.write(e),Q(!0),setTimeout(Q,2e3,!1)}),N(""))},[K,L,H,J]);const ce=i(async(e,o)=>{const t=e.trim();if(t)try{await k(o,t),re(""),ie(0);const e=D(o).label;v({message:`API key de ${e} guardada`,notificationType:"auth_success"},B),r(o)}catch(e){S(e),z({state:"error",message:e.message,toRetry:{state:"provider_api_key_input",provider:o}})}else z({state:"error",message:"Debes ingresar una API key.",toRetry:{state:"provider_api_key_input",provider:o}})},[r,B]),de=i((e,o)=>{const t=e.trim();if(t)try{const e=w(o,t);ae(e),le(0),v({message:`URL de ${D(o).label} guardada`,notificationType:"auth_success"},B),r(o)}catch(e){S(e),z({state:"error",message:e.message,toRetry:{state:"provider_local_setup",provider:o}})}else z({state:"error",message:"Debes ingresar una URL para Ollama.",toRetry:{state:"provider_local_setup",provider:o}})},[r,B]),ue=i(async()=>{z({state:"provider_google_auth_running"});try{if(await A())return void r("gemini-google");const e=await P();x(e);if(!await A())return v({message:"OAuth de Gemini guardado; Code Assist no valido el proyecto de cuota",notificationType:"auth_success"},B),void r("gemini-google");v({message:"Credenciales de Gemini Google listas",notificationType:"auth_success"},B),r("gemini-google")}catch(e){S(e),z({state:"error",message:e.message,toRetry:{state:"provider_google_setup"}})}},[r,B]),me=i(async()=>{try{l("tengu_oauth_flow_start",{loginWithClaudeAi:Y,provider:V});const e=await W.startOAuthFlow(async e=>{z({state:"waiting_for_login",url:e}),setTimeout(Z,3e3,!0)},{loginWithClaudeAi:Y,provider:V,inferenceOnly:"setup-token"===C,expiresIn:"setup-token"===C?31536e3:void 0,orgUUID:G}).catch(e=>{const o=e.message.includes("Token exchange failed"),r=_(e),t=W.getPort(),i="openai"===V&&t?formatOAuthDebugDetails(V,t):"";throw z({state:"error",message:r??(o?"No se pudo intercambiar el codigo de autorizacion por el token de acceso. Intentalo de nuevo."+(i?`\n${i}`:""):e.message),toRetry:"setup-token"===C?{state:"ready_to_start"}:{state:"idle"}}),l("tengu_oauth_token_exchange_error",{error:e.message,ssl_error:null!==r}),e});if("setup-token"===C)z({state:"success",token:e.accessToken});else{z({state:"creating_api_key"});const o=T?I("openai"===V?"openai":"anthropic",T):void 0;if(await c(e,V,o?.id),"anthropic"===V){const e=await O();if(!e.valid)throw new Error(e.message)}z({state:"success"}),v({message:"openai"===V?"Inicio de sesión con OpenAI / Codex completado":"Inicio de sesión en Context Code completado",notificationType:"auth_success"},B)}}catch(e){const o=e.message,r=_(e),t=W.getPort(),i="openai"===V&&t?formatOAuthDebugDetails(V,t):"";z({state:"error",message:r??("openai"===V&&i&&!o.includes("redirect_uri=")?`${o}\n${i}`:o),toRetry:{state:"setup-token"===C?"ready_to_start":"idle"}}),l("tengu_oauth_error",{error:o,ssl_error:null!==r})}},[V,W,Z,Y,C,G,B]),pe=a(!1);return n(()=>{"ready_to_start"!==L.state||pe.current||(pe.current=!0,process.nextTick((e,o)=>{e(),o.current=!1},me,pe))},[L.state,me]),n(()=>{if("setup-token"===C&&"success"===L.state){const e=setTimeout((e,o)=>{l("tengu_oauth_success",{loginWithClaudeAi:e}),o(V)},500,Y,r,V);return()=>clearTimeout(e)}},[C,L,Y,r,V]),n(()=>()=>{W.cleanup()},[W]),e(p,{flexDirection:"column",gap:1,children:["waiting_for_login"===L.state&&H&&e(p,{flexDirection:"column",gap:1,paddingBottom:1,children:[e(p,{paddingX:1,children:[e(g,{dimColor:!0,children:["Browser didn't open? Use the url below to sign in"," "]}),o(g,J?{color:"success",children:"(Copied!)"}:{dimColor:!0,children:o(U,{shortcut:"c",action:"copiar",parens:!0})})]}),o(h,{url:L.url,children:o(g,{dimColor:!0,children:L.url})})]},"urlToCopy"),"setup-token"===C&&"success"===L.state&&L.token&&e(p,{flexDirection:"column",gap:1,paddingTop:1,children:[o(g,{color:"success",children:"✓ Long-lived authentication token created successfully!"}),e(p,{flexDirection:"column",gap:1,children:[o(g,{children:"Your OAuth token (valid for 1 year):"}),o(g,{color:"warning",children:L.token}),o(g,{dimColor:!0,children:"Store this token securely. You won't be able to see it again."}),o(g,{dimColor:!0,children:"Use this token by setting: export CONTEXT_CODE_OAUTH_TOKEN=<token>"})]})]},"tokenOutput"),o(p,{paddingLeft:1,flexDirection:"column",gap:1,children:o(OAuthStatusMessage,{oauthStatus:L,oauthProvider:V,mode:C,startingMessage:t,forcedMethodMessage:E,showPastePrompt:H,pastedCode:K,setPastedCode:N,cursorOffset:F,setCursorOffset:$,textInputColumns:ee,handleSubmitCode:async function(e,o){try{const[r,t]=e.split("#");if(!r||!t)return void z({state:"error",message:"Codigo invalido. Asegurate de copiar el codigo completo",toRetry:{state:"waiting_for_login",url:o}});l("tengu_oauth_manual_entry",{}),W.handleManualAuthCodeInput({authorizationCode:r,state:t})}catch(e){S(e),z({state:"error",message:e.message,toRetry:{state:"waiting_for_login",url:o}})}},setOAuthStatus:z,setLoginWithClaudeAi:q,setOAuthProvider:X,providerApiKey:oe,setProviderApiKey:re,providerApiKeyCursorOffset:te,setProviderApiKeyCursorOffset:ie,handleProviderApiKeySubmit:ce,providerBaseUrl:ne,setProviderBaseUrlInput:ae,providerBaseUrlCursorOffset:se,setProviderBaseUrlCursorOffset:le,handleProviderBaseUrlSubmit:de,onDone:r})})]})}function OAuthStatusMessage(i){const n=t(68),{oauthStatus:a,oauthProvider:s,mode:c,startingMessage:d,forcedMethodMessage:u,showPastePrompt:m,pastedCode:f,setPastedCode:_,cursorOffset:v,setCursorOffset:y,textInputColumns:C,handleSubmitCode:A,setOAuthStatus:x,setLoginWithClaudeAi:k,setOAuthProvider:O,providerApiKey:P,setProviderApiKey:I,providerApiKeyCursorOffset:S,setProviderApiKeyCursorOffset:w,handleProviderApiKeySubmit:j,providerBaseUrl:U,setProviderBaseUrlInput:E,providerBaseUrlCursorOffset:L,setProviderBaseUrlCursorOffset:z,handleProviderBaseUrlSubmit:K,onDone:N}=i;switch(a.state){case"idle":{const r=d||"Context Code puede usarse con tu suscripción de Claude, la facturación de Anthropic Console o OpenAI / Codex OAuth.";let t,i,a,s,c,u,m;return n[0]!==r?(t=o(g,{bold:!0,children:r}),n[0]=r,n[1]=t):t=n[1],n[2]===Symbol.for("react.memo_cache_sentinel")?(i=o(g,{children:"Selecciona el metodo de acceso:"}),n[2]=i):i=n[2],n[3]===Symbol.for("react.memo_cache_sentinel")?(a={label:e(g,{children:["Claude account with subscription ·"," ",o(g,{dimColor:!0,children:"Pro, Max, Team, or Enterprise"}),!1,"\n"]}),value:"claudeai"},n[3]=a):a=n[3],n[4]===Symbol.for("react.memo_cache_sentinel")?(s={label:e(g,{children:["Anthropic Console account ·"," ",o(g,{dimColor:!0,children:"API usage billing"}),"\n"]}),value:"console"},n[4]=s):s=n[4],n[5]===Symbol.for("react.memo_cache_sentinel")?(c=[a,s,{label:e(g,{children:["Cuenta de OpenAI / Codex ·"," ",o(g,{dimColor:!0,children:"Login OAuth"}),"\n"]}),value:"openai"},{label:e(g,{children:["OpenRouter ·"," ",o(g,{dimColor:!0,children:"API key / OpenAI-compatible"}),"\n"]}),value:"openrouter"},{label:e(g,{children:["Ollama ·"," ",o(g,{dimColor:!0,children:"Servidor local compatible"}),"\n"]}),value:"ollama"},{label:e(g,{children:["Gemini API - ",o(g,{dimColor:!0,children:"API key / OpenAI-compatible"}),"\n"]}),value:"gemini-api"},{label:e(g,{children:["Gemini Google - ",o(g,{dimColor:!0,children:"OAuth/ADC de Google"}),"\n"]}),value:"gemini-google"},{label:e(g,{children:["Z.AI ·"," ",o(g,{dimColor:!0,children:"API key / OpenAI-compatible"}),"\n"]}),value:"zai"},{label:e(g,{children:["MiniMax ·"," ",o(g,{dimColor:!0,children:"API key / Anthropic-compatible"}),"\n"]}),value:"minimax"},{label:e(g,{children:["NVIDIA API ·"," ",o(g,{dimColor:!0,children:"API key / build.nvidia.com"}),"\n"]}),value:"nvidia"},{label:e(g,{children:["DeepSeek ·"," ",o(g,{dimColor:!0,children:"API key / contexto 1M (V4)"}),"\n"]}),value:"deepseek"}],n[5]=c):c=n[5],n[6]!==k||n[7]!==x||n[8]!==O||n[65]!==N?(u=o(p,{children:o(M,{options:sortLoginProviderOptions(c),onChange:e=>{"platform"===e?(l("tengu_oauth_platform_selected",{}),x({state:"platform_setup"})):"openai"===e?(l("tengu_oauth_openai_selected",{}),O("openai"),k(!1),x({state:"ready_to_start"})):"openrouter"===e?x({state:"provider_api_key_input",provider:"openrouter"}):"gemini-api"===e||"zai"===e||"minimax"===e||"nvidia"===e||"deepseek"===e?x({state:"provider_api_key_input",provider:e}):"gemini-google"===e?x({state:"provider_google_setup"}):"ollama"===e||"ollama-cloud"===e?(E(T(e)),z(0),x({state:"provider_local_setup",provider:e})):(O("anthropic"),x({state:"ready_to_start"}),"claudeai"===e?(l("tengu_oauth_claudeai_selected",{}),k(!0)):(l("tengu_oauth_console_selected",{}),k(!1)))}})}),n[6]=k,n[7]=x,n[8]=O,n[65]=N,n[66]=u):u=n[66],n[10]!==t||n[11]!==u?(m=e(p,{flexDirection:"column",gap:1,marginTop:1,children:[t,i,u]}),n[10]=t,n[11]=u,n[12]=m):m=n[12],m}case"provider_api_key_input":{let r,t,i,s;if(n[50]!==a.provider?(r=e(g,{bold:!0,children:["Ingresa la API key de ",D(a.provider).label]}),n[50]=a.provider,n[51]=r):r=n[51],n[52]!==a.provider){const r=D(a.provider);t=e(p,{flexDirection:"column",gap:0,children:[o(g,{dimColor:!0,children:r.description}),e(g,{dimColor:!0,children:["Siguiente paso: ",r.setup.nextStep]})]}),n[52]=a.provider,n[53]=t}else t=n[53];return n[54]!==P||n[55]!==S||n[56]!==I||n[57]!==w||n[58]!==C||n[59]!==j?(i=e(p,{children:[o(g,{children:"API key > "}),o(G,{value:P,onChange:I,onSubmit:e=>j(e,a.provider),cursorOffset:S,onChangeCursorOffset:w,columns:C,mask:"*"})]}),n[54]=P,n[55]=S,n[56]=I,n[57]=w,n[58]=C,n[59]=j,n[60]=i):i=n[60],n[61]!==r||n[62]!==t||n[63]!==i?(s=e(p,{flexDirection:"column",gap:1,children:[r,t,i]}),n[61]=r,n[62]=t,n[63]=i,n[64]=s):s=n[64],s}case"provider_local_setup":{const r=D(a.provider);return e(p,{flexDirection:"column",gap:1,children:[o(g,{bold:!0,children:r.label}),o(g,{dimColor:!0,children:r.setup.intro}),o(g,{dimColor:!0,children:r.setup.nextStep}),o(g,{children:"URL del servidor > "}),o(p,{children:o(G,{value:U,onChange:E,onSubmit:e=>K(e,a.provider),cursorOffset:L,onChangeCursorOffset:z,columns:C})}),e(g,{color:"success",children:["Presiona ",o(g,{bold:!0,children:"Enter"})," para guardar la URL y continuar."]})]})}case"provider_google_setup":return e(p,{flexDirection:"column",gap:1,children:[o(g,{bold:!0,children:"Gemini Google OAuth"}),o(g,{dimColor:!0,children:"Context Code usara el flujo OAuth compatible con Gemini CLI y abrira Google en el navegador."}),o(g,{dimColor:!0,children:"Se guardara el access token y refresh token en el perfil activo de Gemini Google."}),e(g,{color:"success",children:["Presiona ",o(g,{bold:!0,children:"Enter"})," para iniciar sesion con tu cuenta de Google."]})]});case"provider_google_auth_running":return e(p,{children:[o(R,{}),o(g,{children:"Abriendo Google OAuth para Gemini..."})]});case"platform_setup":{let r,t,i,a,s,l,c,d;return n[12]===Symbol.for("react.memo_cache_sentinel")?(r=o(g,{bold:!0,children:"Usando plataformas de terceros"}),n[12]=r):r=n[12],n[13]===Symbol.for("react.memo_cache_sentinel")?(t=o(g,{children:"Context Code soporta Amazon Bedrock, Microsoft Foundry y Vertex AI. Configura las variables de entorno requeridas y luego reinicia Context Code."}),i=o(g,{children:"Si formas parte de una organización empresarial, contacta a tu administrador para las instrucciones de configuración."}),n[13]=t,n[14]=i):(t=n[13],i=n[14]),n[15]===Symbol.for("react.memo_cache_sentinel")?(a=o(g,{bold:!0,children:"Documentation:"}),n[15]=a):a=n[15],n[16]===Symbol.for("react.memo_cache_sentinel")?(s=e(g,{children:["· Amazon Bedrock:"," ",o(h,{url:"https://context.iaforged.com/docs/en/amazon-bedrock",children:"https://context.iaforged.com/docs/en/amazon-bedrock"})]}),n[16]=s):s=n[16],n[17]===Symbol.for("react.memo_cache_sentinel")?(l=e(g,{children:["· Microsoft Foundry:"," ",o(h,{url:"https://context.iaforged.com/docs/en/microsoft-foundry",children:"https://context.iaforged.com/docs/en/microsoft-foundry"})]}),n[17]=l):l=n[17],n[18]===Symbol.for("react.memo_cache_sentinel")?(c=e(p,{flexDirection:"column",marginTop:1,children:[a,s,l,e(g,{children:["· Vertex AI:"," ",o(h,{url:"https://context.iaforged.com/docs/en/google-vertex-ai",children:"https://context.iaforged.com/docs/en/google-vertex-ai"})]})]}),n[18]=c):c=n[18],n[19]===Symbol.for("react.memo_cache_sentinel")?(d=e(p,{flexDirection:"column",gap:1,marginTop:1,children:[r,e(p,{flexDirection:"column",gap:1,children:[t,i,c,o(p,{marginTop:1,children:e(g,{dimColor:!0,children:["Presiona ",o(g,{bold:!0,children:"Enter"})," para volver a las opciones de acceso."]})})]})]}),n[19]=d):d=n[19],d}case"waiting_for_login":{let r,t,i,s;return n[20]!==u?(r=u&&o(p,{children:o(g,{dimColor:!0,children:u})}),n[20]=u,n[21]=r):r=n[21],n[22]!==m?(t=!m&&e(p,{children:[o(R,{}),o(g,{children:"Abriendo el navegador para iniciar sesión…"})]}),n[22]=m,n[23]=t):t=n[23],n[24]!==v||n[25]!==A||n[26]!==a.url||n[27]!==f||n[28]!==y||n[29]!==_||n[30]!==m||n[31]!==C?(i=m&&e(p,{children:[o(g,{children:B}),o(G,{value:f,onChange:_,onSubmit:e=>A(e,a.url),cursorOffset:v,onChangeCursorOffset:y,columns:C,mask:"*"})]}),n[24]=v,n[25]=A,n[26]=a.url,n[27]=f,n[28]=y,n[29]=_,n[30]=m,n[31]=C,n[32]=i):i=n[32],n[33]!==r||n[34]!==t||n[35]!==i?(s=e(p,{flexDirection:"column",gap:1,children:[r,t,i]}),n[33]=r,n[34]=t,n[35]=i,n[36]=s):s=n[36],s}case"creating_api_key":{let r;return n[37]===Symbol.for("react.memo_cache_sentinel")?(r=o(p,{flexDirection:"column",gap:1,children:e(p,{children:[o(R,{}),o(g,{children:"Creando API key para Context Code…"})]})}),n[37]=r):r=n[37],r}case"about_to_retry":{let e;return n[38]===Symbol.for("react.memo_cache_sentinel")?(e=o(p,{flexDirection:"column",gap:1,children:o(g,{color:"permission",children:"Reintentando…"})}),n[38]=e):e=n[38],e}case"success":{let t,i;if(n[39]!==c||n[40]!==a.token){const i="openai"===s?"Inicio de sesión en OpenAI / Codex exitoso. Presiona ":"Inicio de sesión exitoso. Presiona ";t="setup-token"===c&&a.token?null:e(r,{children:[b()?.emailAddress?e(g,{dimColor:!0,children:["Sesión iniciada como"," ",o(g,{children:b()?.emailAddress})]}):null,e(g,{color:"success",children:[i,o(g,{bold:!0,children:"Enter"})," para continuar…"]})]}),n[39]=c,n[40]=a.token,n[41]=t}else t=n[41];return n[42]!==t?(i=o(p,{flexDirection:"column",children:t}),n[42]=t,n[43]=i):i=n[43],i}case"error":{let r,t,i;return n[44]!==a.message?(r=e(g,{color:"error",children:["OAuth error: ",a.message]}),n[44]=a.message,n[45]=r):r=n[45],n[46]!==a.toRetry?(t=a.toRetry&&o(p,{marginTop:1,children:e(g,{color:"permission",children:["Press ",o(g,{bold:!0,children:"Enter"})," to retry."]})}),n[46]=a.toRetry,n[47]=t):t=n[47],n[48]!==r||n[49]!==t?(i=e(p,{flexDirection:"column",gap:1,children:[r,t]}),n[48]=r,n[49]=t,n[50]=i):i=n[50],i}default:return null}}
1
+ import{jsxs as e,jsx as o,Fragment as r}from"react/jsx-runtime";import{c as t}from"react/compiler-runtime";import{useCallback as i,useEffect as n,useRef as a,useState as s}from"react";import{logEvent as l}from"../services/analytics/index.js";import{installOAuthTokens as c}from"../cli/handlers/auth.js";import{useTerminalSize as d}from"../hooks/useTerminalSize.js";import{setClipboard as u}from"../ink/termio/osc.js";import{useTerminalNotification as m}from"../ink/useTerminalNotification.js";import{Box as p,Link as h,Text as g}from"../ink.js";import{useKeybinding as f}from"../keybindings/useKeybinding.js";import{getSSLErrorHint as _}from"../services/api/errorUtils.js";import{sendNotification as v}from"../services/notifier.js";import{OAuthService as y}from"../services/oauth/index.js";import{getOAuthRequestDetails as C}from"../services/oauth/client.js";import{checkGeminiGoogleCredentialsValid as A,getOauthAccountInfo as b,saveGeminiGoogleOAuthTokens as x,saveProviderApiKey as k,validateForceLoginOrg as O}from"../utils/auth.js";import{startGeminiCliOAuthFlow as P}from"../services/oauth/geminiCli.js";import{resolveProviderProfile as I}from"../utils/model/providerProfiles.js";import{logError as S}from"../utils/log.js";import{getVisibleProvider as D}from"../utils/model/providerCatalog.js";import{getConfiguredProviderBaseUrl as T,setProviderBaseUrl as w}from"../utils/model/providerBaseUrls.js";import{getSettings_DEPRECATED as j}from"../utils/settings/settings.js";import{Select as M}from"./CustomSelect/select.js";import{KeyboardShortcutHint as U}from"./design-system/KeyboardShortcutHint.js";import{Spinner as R}from"./Spinner.js";import G from"./TextInput.js";const E=["deepseek","minimax","openrouter","zai","nvidia","ollama","openai","claudeai","gemini-google","gemini-api","console"];function sortLoginProviderOptions(e){const o=new Map(E.map((e,o)=>[e,o]));return[...e].sort((e,r)=>(o.get(e.value)??Number.MAX_SAFE_INTEGER)-(o.get(r.value)??Number.MAX_SAFE_INTEGER))}const B="Pega aqui el codigo si se solicita > ";function formatOAuthDebugDetails(e,o){if("openai"!==e)return"";const r=C({provider:e,port:o,isManual:!1});return[`authorize=${r.authorizeUrl}`,`redirect_uri=${r.redirectUri}`,`scope=${r.scopes.join(" ")}`].join("\n")}export function ConsoleOAuthFlow({onDone:r,startingMessage:t,mode:C="login",forceLoginMethod:b,profileName:T}){const M=j()||{},R=b??M.forceLoginMethod,G=M.forceLoginOrgUUID,E="claudeai"===R?"Método de acceso preseleccionado: Plan de suscripción (Context Pro/Max)":"console"===R?"Método de acceso preseleccionado: Facturación por uso de API (Anthropic Console)":"openai"===R?"Método de acceso preseleccionado: OpenAI / Codex OAuth":null,B=m(),[L,K]=s(()=>"setup-token"===C||"claudeai"===R||"console"===R||"openai"===R?{state:"ready_to_start"}:{state:"idle"}),[z,N]=s(""),[F,$]=s(0),[W]=s(()=>new y),[V,X]=s(()=>"openai"===R?"openai":"anthropic"),[Y,q]=s(()=>"setup-token"===C||"claudeai"===R),[H,Z]=s(!1),[J,Q]=s(!1),ee=d().columns-37-1,[oe,re]=s(""),[te,ie]=s(0),[ne,ae]=s(""),[se,le]=s(0);n(()=>{"claudeai"===R?l("tengu_oauth_claudeai_forced",{}):"console"===R&&l("tengu_oauth_console_forced",{})},[R]),n(()=>{if("about_to_retry"===L.state){const e=setTimeout(K,1e3,L.nextState);return()=>clearTimeout(e)}},[L]),f("confirm:yes",()=>{l("tengu_oauth_success",{loginWithClaudeAi:Y}),r(V)},{context:"Confirmation",isActive:"success"===L.state&&"setup-token"!==C}),n(()=>{if("success"===L.state&&!process.stdin.isTTY){const e=setTimeout(()=>{l("tengu_oauth_success",{loginWithClaudeAi:Y}),r(V)},800);return()=>clearTimeout(e)}},[L.state,V,Y,r]),f("confirm:yes",()=>{K({state:"idle"})},{context:"Confirmation",isActive:"platform_setup"===L.state}),f("confirm:yes",()=>{ue()},{context:"Confirmation",isActive:"provider_google_setup"===L.state}),f("confirm:yes",()=>{"error"===L.state&&L.toRetry&&(N(""),K({state:"about_to_retry",nextState:L.toRetry}))},{context:"Confirmation",isActive:"error"===L.state&&!!L.toRetry}),f("cancel",()=>{K({state:"idle"})},{context:"Confirmation",isActive:"provider_api_key_input"===L.state||"provider_local_setup"===L.state||"provider_google_setup"===L.state||"error"===L.state}),n(()=>{"c"===z&&"waiting_for_login"===L.state&&H&&!J&&(u(L.url).then(e=>{e&&process.stdout.write(e),Q(!0),setTimeout(Q,2e3,!1)}),N(""))},[z,L,H,J]);const ce=i(async(e,o)=>{const t=e.trim();if(t)try{await k(o,t),re(""),ie(0);const e=D(o).label;v({message:`API key de ${e} guardada`,notificationType:"auth_success"},B),r(o)}catch(e){S(e),K({state:"error",message:e.message,toRetry:{state:"provider_api_key_input",provider:o}})}else K({state:"error",message:"Debes ingresar una API key.",toRetry:{state:"provider_api_key_input",provider:o}})},[r,B]),de=i((e,o)=>{const t=e.trim();if(t)try{const e=w(o,t);ae(e),le(0),v({message:`URL de ${D(o).label} guardada`,notificationType:"auth_success"},B),r(o)}catch(e){S(e),K({state:"error",message:e.message,toRetry:{state:"provider_local_setup",provider:o}})}else K({state:"error",message:"Debes ingresar una URL para Ollama.",toRetry:{state:"provider_local_setup",provider:o}})},[r,B]),ue=i(async()=>{K({state:"provider_google_auth_running"});try{if(await A())return void r("gemini-google");const e=await P();x(e);if(!await A())return v({message:"OAuth de Gemini guardado; Code Assist no valido el proyecto de cuota",notificationType:"auth_success"},B),void r("gemini-google");v({message:"Credenciales de Gemini Google listas",notificationType:"auth_success"},B),r("gemini-google")}catch(e){S(e),K({state:"error",message:e.message,toRetry:{state:"provider_google_setup"}})}},[r,B]),me=i(async()=>{try{l("tengu_oauth_flow_start",{loginWithClaudeAi:Y,provider:V});const e=await W.startOAuthFlow(async e=>{K({state:"waiting_for_login",url:e}),setTimeout(Z,3e3,!0)},{loginWithClaudeAi:Y,provider:V,inferenceOnly:"setup-token"===C,expiresIn:"setup-token"===C?31536e3:void 0,orgUUID:G}).catch(e=>{const o=e.message.includes("Token exchange failed"),r=_(e),t=W.getPort(),i="openai"===V&&t?formatOAuthDebugDetails(V,t):"";throw K({state:"error",message:r??(o?"No se pudo intercambiar el codigo de autorizacion por el token de acceso. Intentalo de nuevo."+(i?`\n${i}`:""):e.message),toRetry:"setup-token"===C?{state:"ready_to_start"}:{state:"idle"}}),l("tengu_oauth_token_exchange_error",{error:e.message,ssl_error:null!==r}),e});if("setup-token"===C)K({state:"success",token:e.accessToken});else{K({state:"creating_api_key"});const o=T?I("openai"===V?"openai":"anthropic",T):void 0;if(await c(e,V,o?.id),"anthropic"===V){const e=await O();if(!e.valid)throw new Error(e.message)}K({state:"success"}),v({message:"openai"===V?"Inicio de sesión con OpenAI / Codex completado":"Inicio de sesión en Context Code completado",notificationType:"auth_success"},B)}}catch(e){const o=e.message,r=_(e),t=W.getPort(),i="openai"===V&&t?formatOAuthDebugDetails(V,t):"";K({state:"error",message:r??("openai"===V&&i&&!o.includes("redirect_uri=")?`${o}\n${i}`:o),toRetry:{state:"setup-token"===C?"ready_to_start":"idle"}}),l("tengu_oauth_error",{error:o,ssl_error:null!==r})}},[V,W,Z,Y,C,G,B]),pe=a(!1);return n(()=>{"ready_to_start"!==L.state||pe.current||(pe.current=!0,process.nextTick((e,o)=>{e(),o.current=!1},me,pe))},[L.state,me]),n(()=>{if("setup-token"===C&&"success"===L.state){const e=setTimeout((e,o)=>{l("tengu_oauth_success",{loginWithClaudeAi:e}),o(V)},500,Y,r,V);return()=>clearTimeout(e)}},[C,L,Y,r,V]),n(()=>()=>{W.cleanup()},[W]),e(p,{flexDirection:"column",gap:1,children:["waiting_for_login"===L.state&&H&&e(p,{flexDirection:"column",gap:1,paddingBottom:1,children:[e(p,{paddingX:1,children:[e(g,{dimColor:!0,children:["Browser didn't open? Use the url below to sign in"," "]}),o(g,J?{color:"success",children:"(Copied!)"}:{dimColor:!0,children:o(U,{shortcut:"c",action:"copiar",parens:!0})})]}),o(h,{url:L.url,children:o(g,{dimColor:!0,children:L.url})})]},"urlToCopy"),"setup-token"===C&&"success"===L.state&&L.token&&e(p,{flexDirection:"column",gap:1,paddingTop:1,children:[o(g,{color:"success",children:"✓ Long-lived authentication token created successfully!"}),e(p,{flexDirection:"column",gap:1,children:[o(g,{children:"Your OAuth token (valid for 1 year):"}),o(g,{color:"warning",children:L.token}),o(g,{dimColor:!0,children:"Store this token securely. You won't be able to see it again."}),o(g,{dimColor:!0,children:"Use this token by setting: export CONTEXT_CODE_OAUTH_TOKEN=<token>"})]})]},"tokenOutput"),o(p,{paddingLeft:1,flexDirection:"column",gap:1,children:o(OAuthStatusMessage,{oauthStatus:L,oauthProvider:V,mode:C,startingMessage:t,forcedMethodMessage:E,showPastePrompt:H,pastedCode:z,setPastedCode:N,cursorOffset:F,setCursorOffset:$,textInputColumns:ee,handleSubmitCode:async function(e,o){try{const[r,t]=e.split("#");if(!r||!t)return void K({state:"error",message:"Codigo invalido. Asegurate de copiar el codigo completo",toRetry:{state:"waiting_for_login",url:o}});l("tengu_oauth_manual_entry",{}),W.handleManualAuthCodeInput({authorizationCode:r,state:t})}catch(e){S(e),K({state:"error",message:e.message,toRetry:{state:"waiting_for_login",url:o}})}},setOAuthStatus:K,setLoginWithClaudeAi:q,setOAuthProvider:X,providerApiKey:oe,setProviderApiKey:re,providerApiKeyCursorOffset:te,setProviderApiKeyCursorOffset:ie,handleProviderApiKeySubmit:ce,providerBaseUrl:ne,setProviderBaseUrlInput:ae,providerBaseUrlCursorOffset:se,setProviderBaseUrlCursorOffset:le,handleProviderBaseUrlSubmit:de,onDone:r})})]})}function OAuthStatusMessage(i){const n=t(68),{oauthStatus:a,oauthProvider:s,mode:c,startingMessage:d,forcedMethodMessage:u,showPastePrompt:m,pastedCode:f,setPastedCode:_,cursorOffset:v,setCursorOffset:y,textInputColumns:C,handleSubmitCode:A,setOAuthStatus:x,setLoginWithClaudeAi:k,setOAuthProvider:O,providerApiKey:P,setProviderApiKey:I,providerApiKeyCursorOffset:S,setProviderApiKeyCursorOffset:w,handleProviderApiKeySubmit:j,providerBaseUrl:U,setProviderBaseUrlInput:E,providerBaseUrlCursorOffset:L,setProviderBaseUrlCursorOffset:K,handleProviderBaseUrlSubmit:z,onDone:N}=i;switch(a.state){case"idle":{const r=d||"Context Code puede usarse con tu suscripción de Claude, la facturación de Anthropic Console o OpenAI / Codex OAuth.";let t,i,a,s,c,u,m;return n[0]!==r?(t=o(g,{bold:!0,children:r}),n[0]=r,n[1]=t):t=n[1],n[2]===Symbol.for("react.memo_cache_sentinel")?(i=o(g,{children:"Selecciona el metodo de acceso:"}),n[2]=i):i=n[2],n[3]===Symbol.for("react.memo_cache_sentinel")?(a={label:e(g,{children:["Claude account with subscription ·"," ",o(g,{dimColor:!0,children:"Pro, Max, Team, or Enterprise"}),!1,"\n"]}),value:"claudeai"},n[3]=a):a=n[3],n[4]===Symbol.for("react.memo_cache_sentinel")?(s={label:e(g,{children:["Anthropic Console account ·"," ",o(g,{dimColor:!0,children:"API usage billing"}),"\n"]}),value:"console"},n[4]=s):s=n[4],n[5]===Symbol.for("react.memo_cache_sentinel")?(c=[a,s,{label:e(g,{children:["Cuenta de OpenAI / Codex ·"," ",o(g,{dimColor:!0,children:"Login OAuth"}),"\n"]}),value:"openai"},{label:e(g,{children:["OpenRouter ·"," ",o(g,{dimColor:!0,children:"API key / OpenAI-compatible"}),"\n"]}),value:"openrouter"},{label:e(g,{children:["Ollama ·"," ",o(g,{dimColor:!0,children:"Servidor local compatible"}),"\n"]}),value:"ollama"},{label:e(g,{children:["Gemini API - ",o(g,{dimColor:!0,children:"API key / OpenAI-compatible"}),"\n"]}),value:"gemini-api"},{label:e(g,{children:["Gemini Google - ",o(g,{dimColor:!0,children:"OAuth/ADC de Google"}),"\n"]}),value:"gemini-google"},{label:e(g,{children:["Z.AI ·"," ",o(g,{dimColor:!0,children:"API key / OpenAI-compatible"}),"\n"]}),value:"zai"},{label:e(g,{children:["MiniMax ·"," ",o(g,{dimColor:!0,children:"API key / Anthropic-compatible"}),"\n"]}),value:"minimax"},{label:e(g,{children:["NVIDIA API ·"," ",o(g,{dimColor:!0,children:"API key / build.nvidia.com"}),"\n"]}),value:"nvidia"},{label:e(g,{children:["DeepSeek ·"," ",o(g,{dimColor:!0,children:"API key / contexto 1M (V4)"}),"\n"]}),value:"deepseek"}],n[5]=c):c=n[5],n[6]!==k||n[7]!==x||n[8]!==O||n[65]!==N?(u=o(p,{children:o(M,{options:sortLoginProviderOptions(c),onChange:e=>{"platform"===e?(l("tengu_oauth_platform_selected",{}),x({state:"platform_setup"})):"openai"===e?(l("tengu_oauth_openai_selected",{}),O("openai"),k(!1),x({state:"ready_to_start"})):"openrouter"===e?x({state:"provider_api_key_input",provider:"openrouter"}):"gemini-api"===e||"zai"===e||"minimax"===e||"nvidia"===e||"deepseek"===e?x({state:"provider_api_key_input",provider:e}):"gemini-google"===e?x({state:"provider_google_setup"}):"ollama"===e||"ollama-cloud"===e?(E(T(e)),K(0),x({state:"provider_local_setup",provider:e})):(O("anthropic"),x({state:"ready_to_start"}),"claudeai"===e?(l("tengu_oauth_claudeai_selected",{}),k(!0)):(l("tengu_oauth_console_selected",{}),k(!1)))}})}),n[6]=k,n[7]=x,n[8]=O,n[65]=N,n[66]=u):u=n[66],n[10]!==t||n[11]!==u?(m=e(p,{flexDirection:"column",gap:1,marginTop:1,children:[t,i,u]}),n[10]=t,n[11]=u,n[12]=m):m=n[12],m}case"provider_api_key_input":{let r,t,i,s;if(n[50]!==a.provider?(r=e(g,{bold:!0,children:["Ingresa la API key de ",D(a.provider).label]}),n[50]=a.provider,n[51]=r):r=n[51],n[52]!==a.provider){const r=D(a.provider);t=e(p,{flexDirection:"column",gap:0,children:[o(g,{dimColor:!0,children:r.description}),e(g,{dimColor:!0,children:["Siguiente paso: ",r.setup.nextStep]})]}),n[52]=a.provider,n[53]=t}else t=n[53];return n[54]!==P||n[55]!==S||n[56]!==I||n[57]!==w||n[58]!==C||n[59]!==j?(i=e(p,{children:[o(g,{children:"API key > "}),o(G,{value:P,onChange:I,onSubmit:e=>j(e,a.provider),cursorOffset:S,onChangeCursorOffset:w,columns:C,mask:"*"})]}),n[54]=P,n[55]=S,n[56]=I,n[57]=w,n[58]=C,n[59]=j,n[60]=i):i=n[60],n[61]!==r||n[62]!==t||n[63]!==i?(s=e(p,{flexDirection:"column",gap:1,children:[r,t,i]}),n[61]=r,n[62]=t,n[63]=i,n[64]=s):s=n[64],s}case"provider_local_setup":{const r=D(a.provider);return e(p,{flexDirection:"column",gap:1,children:[o(g,{bold:!0,children:r.label}),o(g,{dimColor:!0,children:r.setup.intro}),o(g,{dimColor:!0,children:r.setup.nextStep}),o(g,{children:"URL del servidor > "}),o(p,{children:o(G,{value:U,onChange:E,onSubmit:e=>z(e,a.provider),cursorOffset:L,onChangeCursorOffset:K,columns:C})}),e(g,{color:"success",children:["Presiona ",o(g,{bold:!0,children:"Enter"})," para guardar la URL y continuar."]})]})}case"provider_google_setup":return e(p,{flexDirection:"column",gap:1,children:[o(g,{bold:!0,children:"Gemini Google OAuth"}),o(g,{dimColor:!0,children:"Context Code usara el flujo OAuth compatible con Gemini CLI y abrira Google en el navegador."}),o(g,{dimColor:!0,children:"Se guardara el access token y refresh token en el perfil activo de Gemini Google."}),e(g,{color:"success",children:["Presiona ",o(g,{bold:!0,children:"Enter"})," para iniciar sesion con tu cuenta de Google."]})]});case"provider_google_auth_running":return e(p,{children:[o(R,{}),o(g,{children:"Abriendo Google OAuth para Gemini..."})]});case"platform_setup":{let r,t,i,a,s,l,c,d;return n[12]===Symbol.for("react.memo_cache_sentinel")?(r=o(g,{bold:!0,children:"Usando plataformas de terceros"}),n[12]=r):r=n[12],n[13]===Symbol.for("react.memo_cache_sentinel")?(t=o(g,{children:"Context Code soporta Amazon Bedrock, Microsoft Foundry y Vertex AI. Configura las variables de entorno requeridas y luego reinicia Context Code."}),i=o(g,{children:"Si formas parte de una organización empresarial, contacta a tu administrador para las instrucciones de configuración."}),n[13]=t,n[14]=i):(t=n[13],i=n[14]),n[15]===Symbol.for("react.memo_cache_sentinel")?(a=o(g,{bold:!0,children:"Documentation:"}),n[15]=a):a=n[15],n[16]===Symbol.for("react.memo_cache_sentinel")?(s=e(g,{children:["· Amazon Bedrock:"," ",o(h,{url:"https://docs.iaforged.com/",children:"https://docs.iaforged.com/"})]}),n[16]=s):s=n[16],n[17]===Symbol.for("react.memo_cache_sentinel")?(l=e(g,{children:["· Microsoft Foundry:"," ",o(h,{url:"https://docs.iaforged.com/",children:"https://docs.iaforged.com/"})]}),n[17]=l):l=n[17],n[18]===Symbol.for("react.memo_cache_sentinel")?(c=e(p,{flexDirection:"column",marginTop:1,children:[a,s,l,e(g,{children:["· Vertex AI:"," ",o(h,{url:"https://docs.iaforged.com/",children:"https://docs.iaforged.com/"})]})]}),n[18]=c):c=n[18],n[19]===Symbol.for("react.memo_cache_sentinel")?(d=e(p,{flexDirection:"column",gap:1,marginTop:1,children:[r,e(p,{flexDirection:"column",gap:1,children:[t,i,c,o(p,{marginTop:1,children:e(g,{dimColor:!0,children:["Presiona ",o(g,{bold:!0,children:"Enter"})," para volver a las opciones de acceso."]})})]})]}),n[19]=d):d=n[19],d}case"waiting_for_login":{let r,t,i,s;return n[20]!==u?(r=u&&o(p,{children:o(g,{dimColor:!0,children:u})}),n[20]=u,n[21]=r):r=n[21],n[22]!==m?(t=!m&&e(p,{children:[o(R,{}),o(g,{children:"Abriendo el navegador para iniciar sesión…"})]}),n[22]=m,n[23]=t):t=n[23],n[24]!==v||n[25]!==A||n[26]!==a.url||n[27]!==f||n[28]!==y||n[29]!==_||n[30]!==m||n[31]!==C?(i=m&&e(p,{children:[o(g,{children:B}),o(G,{value:f,onChange:_,onSubmit:e=>A(e,a.url),cursorOffset:v,onChangeCursorOffset:y,columns:C,mask:"*"})]}),n[24]=v,n[25]=A,n[26]=a.url,n[27]=f,n[28]=y,n[29]=_,n[30]=m,n[31]=C,n[32]=i):i=n[32],n[33]!==r||n[34]!==t||n[35]!==i?(s=e(p,{flexDirection:"column",gap:1,children:[r,t,i]}),n[33]=r,n[34]=t,n[35]=i,n[36]=s):s=n[36],s}case"creating_api_key":{let r;return n[37]===Symbol.for("react.memo_cache_sentinel")?(r=o(p,{flexDirection:"column",gap:1,children:e(p,{children:[o(R,{}),o(g,{children:"Creando API key para Context Code…"})]})}),n[37]=r):r=n[37],r}case"about_to_retry":{let e;return n[38]===Symbol.for("react.memo_cache_sentinel")?(e=o(p,{flexDirection:"column",gap:1,children:o(g,{color:"permission",children:"Reintentando…"})}),n[38]=e):e=n[38],e}case"success":{let t,i;if(n[39]!==c||n[40]!==a.token){const i="openai"===s?"Inicio de sesión en OpenAI / Codex exitoso. Presiona ":"Inicio de sesión exitoso. Presiona ";t="setup-token"===c&&a.token?null:e(r,{children:[b()?.emailAddress?e(g,{dimColor:!0,children:["Sesión iniciada como"," ",o(g,{children:b()?.emailAddress})]}):null,e(g,{color:"success",children:[i,o(g,{bold:!0,children:"Enter"})," para continuar…"]})]}),n[39]=c,n[40]=a.token,n[41]=t}else t=n[41];return n[42]!==t?(i=o(p,{flexDirection:"column",children:t}),n[42]=t,n[43]=i):i=n[43],i}case"error":{let r,t,i;return n[44]!==a.message?(r=e(g,{color:"error",children:["OAuth error: ",a.message]}),n[44]=a.message,n[45]=r):r=n[45],n[46]!==a.toRetry?(t=a.toRetry&&o(p,{marginTop:1,children:e(g,{color:"permission",children:["Press ",o(g,{bold:!0,children:"Enter"})," to retry."]})}),n[46]=a.toRetry,n[47]=t):t=n[47],n[48]!==r||n[49]!==t?(i=e(p,{flexDirection:"column",gap:1,children:[r,t]}),n[48]=r,n[49]=t,n[50]=i):i=n[50],i}default:return null}}
@@ -1 +1 @@
1
- import{MACRO as e}from"../../recovery/bunBundleShim.js";import{jsx as o,jsxs as n,Fragment as s}from"react/jsx-runtime";import{c as r}from"react/compiler-runtime";import{useExitOnCtrlCDWithKeybindings as i}from"../../hooks/useExitOnCtrlCDWithKeybindings.js";import{useShortcutDisplay as t}from"../../keybindings/useShortcutDisplay.js";import{builtInCommandNames as m}from"../../commands.js";import{useIsInsideModal as a}from"../../context/modalContext.js";import{useTerminalSize as l}from"../../hooks/useTerminalSize.js";import{Box as c,Link as d,Text as p}from"../../ink.js";import{useKeybinding as h}from"../../keybindings/useKeybinding.js";import{Pane as f}from"../design-system/Pane.js";import{Tab as u,Tabs as y}from"../design-system/Tabs.js";import{Commands as g}from"./Commands.js";import{General as j}from"./General.js";export function HelpV2(x){const b=r(44),{onClose:C,commands:k}=x,{rows:S,columns:_}=l(),v=Math.floor(S/2),H=a();let N;b[0]!==C?(N=()=>C("Diálogo de ayuda descartado",{display:"system"}),b[0]=C,b[1]=N):N=b[1];const T=N;let z;b[2]===Symbol.for("react.memo_cache_sentinel")?(z={context:"Ayuda"},b[2]=z):z=b[2],h("help:dismiss",T,z);const D=i(T),E=t("help:dismiss","Ayuda","esc");let B,P,w;if(b[3]!==k){const e=m();let o;P=k.filter(o=>e.has(o.name)&&!o.isHidden),b[7]===Symbol.for("react.memo_cache_sentinel")?(o=[],b[7]=o):o=b[7],B=o,w=k.filter(o=>!e.has(o.name)&&!o.isHidden),b[3]=k,b[4]=B,b[5]=P,b[6]=w}else B=b[4],P=b[5],w=b[6];const A=w;let K,M;if(b[8]===Symbol.for("react.memo_cache_sentinel")?(K=o(u,{title:"general",children:o(j,{})},"general"),b[8]=K):K=b[8],b[9]!==B||b[10]!==P||b[11]!==T||b[12]!==_||b[13]!==A||b[14]!==v){let e,n;M=[K],b[16]!==P||b[17]!==T||b[18]!==_||b[19]!==v?(e=o(u,{title:"comandos",children:o(g,{commands:P,maxHeight:v,columns:_,title:"Explorar comandos predeterminados:",onCancel:T})},"commands"),b[16]=P,b[17]=T,b[18]=_,b[19]=v,b[20]=e):e=b[20],M.push(e),b[21]!==T||b[22]!==_||b[23]!==A||b[24]!==v?(n=o(u,{title:"personalizados",children:o(g,{commands:A,maxHeight:v,columns:_,title:"Explorar comandos personalizados:",emptyMessage:"No se encontraron comandos personalizados",onCancel:T})},"custom"),b[21]=T,b[22]=_,b[23]=A,b[24]=v,b[25]=n):n=b[25],M.push(n),b[9]=B,b[10]=P,b[11]=T,b[12]=_,b[13]=A,b[14]=v,b[15]=M}else M=b[15];const O=H?void 0:v;let V,F,G,I,R;return b[31]!==M?(V=o(y,{title:`Context Code v${e.VERSION}`,color:"professionalBlue",defaultTab:"general",children:M}),b[31]=M,b[32]=V):V=b[32],b[33]===Symbol.for("react.memo_cache_sentinel")?(F=o(c,{marginTop:1,children:n(p,{children:["Para más ayuda:"," ",o(d,{url:"https://context.iaforged.com/docs/en/overview"})]})}),b[33]=F):F=b[33],b[34]!==E||b[35]!==D.keyName||b[36]!==D.pending?(G=o(c,{marginTop:1,children:o(p,{dimColor:!0,children:D.pending?n(s,{children:["Presione ",D.keyName," de nuevo para salir"]}):n(p,{italic:!0,children:[E," para cancelar"]})})}),b[34]=E,b[35]=D.keyName,b[36]=D.pending,b[37]=G):G=b[37],b[38]!==V||b[39]!==G?(I=n(f,{color:"professionalBlue",children:[V,F,G]}),b[38]=V,b[39]=G,b[40]=I):I=b[40],b[41]!==O||b[42]!==I?(R=o(c,{flexDirection:"column",height:O,children:I}),b[41]=O,b[42]=I,b[43]=R):R=b[43],R}
1
+ import{MACRO as e}from"../../recovery/bunBundleShim.js";import{jsx as o,jsxs as s,Fragment as n}from"react/jsx-runtime";import{c as r}from"react/compiler-runtime";import{useExitOnCtrlCDWithKeybindings as i}from"../../hooks/useExitOnCtrlCDWithKeybindings.js";import{useShortcutDisplay as m}from"../../keybindings/useShortcutDisplay.js";import{builtInCommandNames as t}from"../../commands.js";import{useIsInsideModal as a}from"../../context/modalContext.js";import{useTerminalSize as l}from"../../hooks/useTerminalSize.js";import{Box as c,Link as d,Text as p}from"../../ink.js";import{useKeybinding as h}from"../../keybindings/useKeybinding.js";import{Pane as f}from"../design-system/Pane.js";import{Tab as u,Tabs as y}from"../design-system/Tabs.js";import{Commands as g}from"./Commands.js";import{General as j}from"./General.js";export function HelpV2(x){const b=r(44),{onClose:C,commands:k}=x,{rows:S,columns:_}=l(),H=Math.floor(S/2),N=a();let T;b[0]!==C?(T=()=>C("Diálogo de ayuda descartado",{display:"system"}),b[0]=C,b[1]=T):T=b[1];const v=T;let z;b[2]===Symbol.for("react.memo_cache_sentinel")?(z={context:"Ayuda"},b[2]=z):z=b[2],h("help:dismiss",v,z);const D=i(v),E=m("help:dismiss","Ayuda","esc");let B,P,A;if(b[3]!==k){const e=t();let o;P=k.filter(o=>e.has(o.name)&&!o.isHidden),b[7]===Symbol.for("react.memo_cache_sentinel")?(o=[],b[7]=o):o=b[7],B=o,A=k.filter(o=>!e.has(o.name)&&!o.isHidden),b[3]=k,b[4]=B,b[5]=P,b[6]=A}else B=b[4],P=b[5],A=b[6];const K=A;let M,O;if(b[8]===Symbol.for("react.memo_cache_sentinel")?(M=o(u,{title:"general",children:o(j,{})},"general"),b[8]=M):M=b[8],b[9]!==B||b[10]!==P||b[11]!==v||b[12]!==_||b[13]!==K||b[14]!==H){let e,s;O=[M],b[16]!==P||b[17]!==v||b[18]!==_||b[19]!==H?(e=o(u,{title:"comandos",children:o(g,{commands:P,maxHeight:H,columns:_,title:"Explorar comandos predeterminados:",onCancel:v})},"commands"),b[16]=P,b[17]=v,b[18]=_,b[19]=H,b[20]=e):e=b[20],O.push(e),b[21]!==v||b[22]!==_||b[23]!==K||b[24]!==H?(s=o(u,{title:"personalizados",children:o(g,{commands:K,maxHeight:H,columns:_,title:"Explorar comandos personalizados:",emptyMessage:"No se encontraron comandos personalizados",onCancel:v})},"custom"),b[21]=v,b[22]=_,b[23]=K,b[24]=H,b[25]=s):s=b[25],O.push(s),b[9]=B,b[10]=P,b[11]=v,b[12]=_,b[13]=K,b[14]=H,b[15]=O}else O=b[15];const V=N?void 0:H;let w,F,G,I,R;return b[31]!==O?(w=o(y,{title:`Context Code v${e.VERSION}`,color:"professionalBlue",defaultTab:"general",children:O}),b[31]=O,b[32]=w):w=b[32],b[33]===Symbol.for("react.memo_cache_sentinel")?(F=o(c,{marginTop:1,children:s(p,{children:["Para más ayuda:"," ",o(d,{url:"https://docs.iaforged.com/"})]})}),b[33]=F):F=b[33],b[34]!==E||b[35]!==D.keyName||b[36]!==D.pending?(G=o(c,{marginTop:1,children:o(p,{dimColor:!0,children:D.pending?s(n,{children:["Presione ",D.keyName," de nuevo para salir"]}):s(p,{italic:!0,children:[E," para cancelar"]})})}),b[34]=E,b[35]=D.keyName,b[36]=D.pending,b[37]=G):G=b[37],b[38]!==w||b[39]!==G?(I=s(f,{color:"professionalBlue",children:[w,F,G]}),b[38]=w,b[39]=G,b[40]=I):I=b[40],b[41]!==V||b[42]!==I?(R=o(c,{flexDirection:"column",height:V,children:I}),b[41]=V,b[42]=I,b[43]=R):R=b[43],R}
@@ -1 +1 @@
1
- import{A as e,Aa as r,Ba as i,C as a,Ca as o,Da as l,Ea as u,J as h,P as p,Q as b,a as g,aa as w,c as d,d as v,f as E,h as f,i as m,j as y,k as O,l as k,m as T,o as C,pa as A,q as I,r as P,s as S,t as M,wa as N,xa as D,ya as W,za as L}from"./chunk-VAB2VXFI.js";var _="Service workers are disabled or not supported by this browser",x=class{serviceWorker;worker;registration;events;constructor(e,r){if(this.serviceWorker=e,e){let i=null,a=new v;this.worker=new d(e=>(null!==i&&e.next(i),a.subscribe(r=>e.next(r))));let s=()=>{let{controller:r}=e;null!==r&&(i=r,a.next(i))};e.addEventListener("controllerchange",s),s(),this.registration=this.worker.pipe(O(()=>e.getRegistration()));let o=new v;this.events=o.asObservable();let c=e=>{let{data:r}=e;r?.type&&o.next(r)};e.addEventListener("message",c),r?.get(b,null,{optional:!0})?.onDestroy(()=>{e.removeEventListener("controllerchange",s),e.removeEventListener("message",c)})}else this.worker=this.events=this.registration=new d(e=>e.error(new k(5601,!1)))}postMessage(e,r){return new Promise(i=>{this.worker.pipe(y(1)).subscribe(a=>{a.postMessage(g({action:e},r)),i()})})}postMessageWithOperation(e,r,i){let a=this.waitForOperationCompleted(i),o=this.postMessage(e,r);return Promise.all([o,a]).then(([,e])=>e)}generateNonce(){return Math.round(1e7*Math.random())}eventsOfType(e){let r;return r="string"==typeof e?r=>r.type===e:r=>e.includes(r.type),this.events.pipe(m(r))}nextEventOfType(e){return this.eventsOfType(e).pipe(y(1))}waitForOperationCompleted(e){return new Promise((r,i)=>{this.eventsOfType("OPERATION_COMPLETED").pipe(m(r=>r.nonce===e),y(1),E(e=>{if(void 0!==e.result)return e.result;throw new Error(e.error)})).subscribe({next:r,error:i})})}get isEnabled(){return!!this.serviceWorker}},V=(()=>{class n{sw;messages;notificationClicks;subscription;get isEnabled(){return this.sw.isEnabled}pushManager=null;subscriptionChanges=new v;constructor(e){if(this.sw=e,!e.isEnabled)return this.messages=f,this.notificationClicks=f,void(this.subscription=f);this.messages=this.sw.eventsOfType("PUSH").pipe(E(e=>e.data)),this.notificationClicks=this.sw.eventsOfType("NOTIFICATION_CLICK").pipe(E(e=>e.data)),this.pushManager=this.sw.registration.pipe(E(e=>e.pushManager));let r=this.pushManager.pipe(O(e=>e.getSubscription()));this.subscription=new d(e=>{let i=r.subscribe(e),a=this.subscriptionChanges.subscribe(e);return()=>{i.unsubscribe(),a.unsubscribe()}})}requestSubscription(e){if(!this.sw.isEnabled||null===this.pushManager)return Promise.reject(new Error(_));let r={userVisibleOnly:!0},i=this.decodeBase64(e.serverPublicKey.replace(/_/g,"/").replace(/-/g,"+")),a=new Uint8Array(new ArrayBuffer(i.length));for(let e=0;e<i.length;e++)a[e]=i.charCodeAt(e);return r.applicationServerKey=a,new Promise((e,i)=>{this.pushManager.pipe(O(e=>e.subscribe(r)),y(1)).subscribe({next:r=>{this.subscriptionChanges.next(r),e(r)},error:i})})}unsubscribe(){if(!this.sw.isEnabled)return Promise.reject(new Error(_));let t=e=>{if(null===e)throw new k(5602,!1);return e.unsubscribe().then(e=>{if(!e)throw new k(5603,!1);this.subscriptionChanges.next(null)})};return new Promise((e,r)=>{this.subscription.pipe(y(1),O(t)).subscribe({next:e,error:r})})}decodeBase64(e){return atob(e)}static ɵfac=function(e){return new(e||n)(P(x))};static ɵprov=C({token:n,factory:n.ɵfac})}return n})(),F=(()=>{class n{sw;versionUpdates;unrecoverable;get isEnabled(){return this.sw.isEnabled}constructor(e){if(this.sw=e,!e.isEnabled)return this.versionUpdates=f,void(this.unrecoverable=f);this.versionUpdates=this.sw.eventsOfType(["VERSION_DETECTED","VERSION_INSTALLATION_FAILED","VERSION_READY","NO_NEW_VERSION_DETECTED"]),this.unrecoverable=this.sw.eventsOfType("UNRECOVERABLE_STATE")}checkForUpdate(){if(!this.sw.isEnabled)return Promise.reject(new Error(_));let e=this.sw.generateNonce();return this.sw.postMessageWithOperation("CHECK_FOR_UPDATES",{nonce:e},e)}activateUpdate(){if(!this.sw.isEnabled)return Promise.reject(new k(5601,!1));let e=this.sw.generateNonce();return this.sw.postMessageWithOperation("ACTIVATE_UPDATE",{nonce:e},e)}static ɵfac=function(e){return new(e||n)(P(x))};static ɵprov=C({token:n,factory:n.ɵfac})}return n})(),R=new I("");function X(){let e=S(U);if(!("serviceWorker"in navigator)||!1===e.enabled)return;let r=S(R),i=S(a),o=S(b);i.runOutsideAngular(()=>{let e=navigator.serviceWorker,s=()=>e.controller?.postMessage({action:"INITIALIZE"});e.addEventListener("controllerchange",s),o.onDestroy(()=>{e.removeEventListener("controllerchange",s)})}),i.runOutsideAngular(()=>{let i,{registrationStrategy:a}=e;if("function"==typeof a)i=new Promise(e=>a().subscribe(()=>e()));else{let[e,...r]=(a||"registerWhenStable:30000").split(":");switch(e){case"registerImmediately":i=Promise.resolve();break;case"registerWithDelay":i=q(+r[0]||0);break;case"registerWhenStable":i=Promise.race([o.whenStable(),q(+r[0])]);break;default:throw new k(5600,!1)}}i.then(()=>{o.destroyed||navigator.serviceWorker.register(r,{scope:e.scope}).catch(e=>console.error(T(5604,!1)))})})}function q(e){return new Promise(r=>setTimeout(r,e))}function ee(e,r){return new x(!1!==e.enabled?navigator.serviceWorker:void 0,r)}var U=class{enabled;scope;registrationStrategy};N(class n{constructor(){this.auth=S(l),this.socket=S(u)}ngOnInit(){this.auth.hasToken()&&this.socket.connect()}static{this.ɵfac=function(e){return new(e||n)}}static{this.ɵcmp=h({type:n,selectors:[["cx-root"]],decls:1,vars:0,template:function(e,r){1&e&&w(0,"router-outlet")},dependencies:[L],encapsulation:2,changeDetection:0})}},{providers:[i([{path:"",redirectTo:"chat",pathMatch:"full"},{path:"login",loadComponent:()=>import("./chunk-NFYBHCXF.js").then(e=>e.LoginComponent)},{path:"chat",canActivate:[()=>{let e=S(l),i=S(r);return!!e.hasToken()||(i.navigate(["/login"]),!1)}],loadComponent:()=>import("./chunk-AMCDNAIG.js").then(e=>e.ChatComponent)},{path:"**",redirectTo:"chat"}],o()),D(W()),function(r,i={}){return M([V,F,{provide:R,useValue:r},{provide:U,useValue:i},{provide:x,useFactory:ee,deps:[U,e]},p(X)])}("ngsw-worker.js",{enabled:!A(),registrationStrategy:"registerWhenStable:30000"})]}).catch(e=>console.error("[webapp] bootstrap error",e));
1
+ import{A as e,Aa as r,Ba as i,C as a,Ca as o,Da as l,Ea as u,J as h,P as p,Q as b,a as g,aa as w,c as d,d as v,f,h as E,i as m,j as y,k,l as O,m as T,o as C,pa as A,q as I,r as P,s as S,t as M,wa as N,xa as D,ya as W,za as L}from"./chunk-VAB2VXFI.js";var _="Service workers are disabled or not supported by this browser",x=class{serviceWorker;worker;registration;events;constructor(e,r){if(this.serviceWorker=e,e){let i=null,a=new v;this.worker=new d(e=>(null!==i&&e.next(i),a.subscribe(r=>e.next(r))));let s=()=>{let{controller:r}=e;null!==r&&(i=r,a.next(i))};e.addEventListener("controllerchange",s),s(),this.registration=this.worker.pipe(k(()=>e.getRegistration()));let o=new v;this.events=o.asObservable();let c=e=>{let{data:r}=e;r?.type&&o.next(r)};e.addEventListener("message",c),r?.get(b,null,{optional:!0})?.onDestroy(()=>{e.removeEventListener("controllerchange",s),e.removeEventListener("message",c)})}else this.worker=this.events=this.registration=new d(e=>e.error(new O(5601,!1)))}postMessage(e,r){return new Promise(i=>{this.worker.pipe(y(1)).subscribe(a=>{a.postMessage(g({action:e},r)),i()})})}postMessageWithOperation(e,r,i){let a=this.waitForOperationCompleted(i),o=this.postMessage(e,r);return Promise.all([o,a]).then(([,e])=>e)}generateNonce(){return Math.round(1e7*Math.random())}eventsOfType(e){let r;return r="string"==typeof e?r=>r.type===e:r=>e.includes(r.type),this.events.pipe(m(r))}nextEventOfType(e){return this.eventsOfType(e).pipe(y(1))}waitForOperationCompleted(e){return new Promise((r,i)=>{this.eventsOfType("OPERATION_COMPLETED").pipe(m(r=>r.nonce===e),y(1),f(e=>{if(void 0!==e.result)return e.result;throw new Error(e.error)})).subscribe({next:r,error:i})})}get isEnabled(){return!!this.serviceWorker}},V=(()=>{class n{sw;messages;notificationClicks;subscription;get isEnabled(){return this.sw.isEnabled}pushManager=null;subscriptionChanges=new v;constructor(e){if(this.sw=e,!e.isEnabled)return this.messages=E,this.notificationClicks=E,void(this.subscription=E);this.messages=this.sw.eventsOfType("PUSH").pipe(f(e=>e.data)),this.notificationClicks=this.sw.eventsOfType("NOTIFICATION_CLICK").pipe(f(e=>e.data)),this.pushManager=this.sw.registration.pipe(f(e=>e.pushManager));let r=this.pushManager.pipe(k(e=>e.getSubscription()));this.subscription=new d(e=>{let i=r.subscribe(e),a=this.subscriptionChanges.subscribe(e);return()=>{i.unsubscribe(),a.unsubscribe()}})}requestSubscription(e){if(!this.sw.isEnabled||null===this.pushManager)return Promise.reject(new Error(_));let r={userVisibleOnly:!0},i=this.decodeBase64(e.serverPublicKey.replace(/_/g,"/").replace(/-/g,"+")),a=new Uint8Array(new ArrayBuffer(i.length));for(let e=0;e<i.length;e++)a[e]=i.charCodeAt(e);return r.applicationServerKey=a,new Promise((e,i)=>{this.pushManager.pipe(k(e=>e.subscribe(r)),y(1)).subscribe({next:r=>{this.subscriptionChanges.next(r),e(r)},error:i})})}unsubscribe(){if(!this.sw.isEnabled)return Promise.reject(new Error(_));let t=e=>{if(null===e)throw new O(5602,!1);return e.unsubscribe().then(e=>{if(!e)throw new O(5603,!1);this.subscriptionChanges.next(null)})};return new Promise((e,r)=>{this.subscription.pipe(y(1),k(t)).subscribe({next:e,error:r})})}decodeBase64(e){return atob(e)}static ɵfac=function(e){return new(e||n)(P(x))};static ɵprov=C({token:n,factory:n.ɵfac})}return n})(),F=(()=>{class n{sw;versionUpdates;unrecoverable;get isEnabled(){return this.sw.isEnabled}constructor(e){if(this.sw=e,!e.isEnabled)return this.versionUpdates=E,void(this.unrecoverable=E);this.versionUpdates=this.sw.eventsOfType(["VERSION_DETECTED","VERSION_INSTALLATION_FAILED","VERSION_READY","NO_NEW_VERSION_DETECTED"]),this.unrecoverable=this.sw.eventsOfType("UNRECOVERABLE_STATE")}checkForUpdate(){if(!this.sw.isEnabled)return Promise.reject(new Error(_));let e=this.sw.generateNonce();return this.sw.postMessageWithOperation("CHECK_FOR_UPDATES",{nonce:e},e)}activateUpdate(){if(!this.sw.isEnabled)return Promise.reject(new O(5601,!1));let e=this.sw.generateNonce();return this.sw.postMessageWithOperation("ACTIVATE_UPDATE",{nonce:e},e)}static ɵfac=function(e){return new(e||n)(P(x))};static ɵprov=C({token:n,factory:n.ɵfac})}return n})(),R=new I("");function X(){let e=S(U);if(!("serviceWorker"in navigator)||!1===e.enabled)return;let r=S(R),i=S(a),o=S(b);i.runOutsideAngular(()=>{let e=navigator.serviceWorker,s=()=>e.controller?.postMessage({action:"INITIALIZE"});e.addEventListener("controllerchange",s),o.onDestroy(()=>{e.removeEventListener("controllerchange",s)})}),i.runOutsideAngular(()=>{let i,{registrationStrategy:a}=e;if("function"==typeof a)i=new Promise(e=>a().subscribe(()=>e()));else{let[e,...r]=(a||"registerWhenStable:30000").split(":");switch(e){case"registerImmediately":i=Promise.resolve();break;case"registerWithDelay":i=q(+r[0]||0);break;case"registerWhenStable":i=Promise.race([o.whenStable(),q(+r[0])]);break;default:throw new O(5600,!1)}}i.then(()=>{o.destroyed||navigator.serviceWorker.register(r,{scope:e.scope}).catch(e=>console.error(T(5604,!1)))})})}function q(e){return new Promise(r=>setTimeout(r,e))}function ee(e,r){return new x(!1!==e.enabled?navigator.serviceWorker:void 0,r)}var U=class{enabled;scope;registrationStrategy};N(class n{constructor(){this.auth=S(l),this.socket=S(u)}ngOnInit(){this.auth.hasToken()&&this.socket.connect()}static{this.ɵfac=function(e){return new(e||n)}}static{this.ɵcmp=h({type:n,selectors:[["cx-root"]],decls:1,vars:0,template:function(e,r){1&e&&w(0,"router-outlet")},dependencies:[L],encapsulation:2,changeDetection:0})}},{providers:[i([{path:"",redirectTo:"chat",pathMatch:"full"},{path:"login",loadComponent:()=>import("./chunk-NFYBHCXF.js").then(e=>e.LoginComponent)},{path:"chat",canActivate:[()=>{let e=S(l),i=S(r);return!!e.hasToken()||(i.navigate(["/login"]),!1)}],loadComponent:()=>import("./chunk-AMCDNAIG.js").then(e=>e.ChatComponent)},{path:"**",redirectTo:"chat"}],o()),D(W()),function(r,i={}){return M([V,F,{provide:R,useValue:r},{provide:U,useValue:i},{provide:x,useFactory:ee,deps:[U,e]},p(X)])}("ngsw-worker.js",{enabled:!A(),registrationStrategy:"registerWhenStable:30000"})]}).catch(e=>console.error("[webapp] bootstrap error",e));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iaforged/context-code",
3
- "version": "2.0.9",
3
+ "version": "2.1.0",
4
4
  "description": "Context Code es un asistente de desarrollo para la terminal. Puede revisar tu proyecto, editar archivos, ejecutar comandos y apoyarte en tareas reales de programacion.",
5
5
  "author": "Context AI",
6
6
  "license": "MIT",
@@ -17,7 +17,6 @@
17
17
  "context-bootstrap.js",
18
18
  "contextcode-bootstrap.js",
19
19
  "dist/",
20
- "docs/",
21
20
  "README.md",
22
21
  "LICENSE.md"
23
22
  ],
package/docs/BRIDGES.md DELETED
@@ -1,90 +0,0 @@
1
- ## Puentes con mensajería móvil
2
-
3
- Context Code puede conectarse con **Telegram** y **WhatsApp** para que veas y respondas la conversación completa desde tu móvil. Cada mensaje que escribes en la terminal se refleja en el chat, cada respuesta del modelo llega de vuelta, y cada herramienta que ejecuta el asistente (Bash, Read, Edit…) se resume en una línea. También puedes escribir **desde el móvil** y el texto se inyecta al REPL como si lo hubieras tecleado en la terminal — la conversación es la misma, da igual por dónde entres.
4
-
5
- Los dos puentes funcionan de forma independiente: puedes usar solo Telegram, solo WhatsApp, o los dos a la vez.
6
-
7
- ### Qué se sincroniza
8
-
9
- - **De la terminal al móvil:** tus prompts (`👤`), las respuestas de texto del modelo (`🤖`) y una línea por cada tool call (`🔧 Bash: npm test`, `🔧 Read: src/foo.ts`, etc.). No se manda el output crudo de las herramientas para no saturar el chat.
10
- - **Del móvil a la terminal:** cualquier texto que envíes aterriza en la cola de entrada del REPL con la misma prioridad que si lo hubieras escrito en la CLI.
11
- - **Antiduplicado:** si escribes desde el móvil, ese texto no se reenvía de vuelta al mismo canal. El otro canal sí lo recibe (si está activo).
12
- - **Código no sincronizado:** mensajes internos del sistema, salidas de slash commands y otros eventos auxiliares no se envían a los canales.
13
-
14
- ### `/telegram` — Bridge con Telegram
15
-
16
- Usa la [Bot API oficial de Telegram](https://core.telegram.org/bots/api) vía `grammy`. Requiere crear un bot en **@BotFather** y darle al wizard el token.
17
-
18
- Flujo en 3 pasos:
19
-
20
- 1. **Intro** con instrucciones para crear el bot en `@BotFather` (`/newbot`, nombre, username, token).
21
- 2. **Pegar el token** — input con validación de formato `123456789:ABC-...`.
22
- 3. **Iniciar bot** — el bridge queda corriendo.
23
-
24
- Desde el móvil, envía `/start` al bot y ese chat queda registrado como destinatario primario. El bot también responde a `/status`, `/model <nombre>` y `/provider <nombre>` para cambiar proveedor o modelo desde Telegram.
25
-
26
- Comandos dentro de la CLI:
27
-
28
- ```
29
- /telegram # abre el wizard (alias: /tele, /bot)
30
- ```
31
-
32
- El token queda guardado localmente en la config (`~/.context/...`) y nunca sale del equipo.
33
-
34
- ### `/whatsapp` — Bridge con WhatsApp
35
-
36
- Usa **Baileys** (`@whiskeysockets/baileys`) vía WhatsApp Web para vincular una cuenta como dispositivo enlazado. Baileys es **opcional**: solo se carga cuando ejecutas `/whatsapp` por primera vez, así no pesa en la instalación base. El QR se dibuja en la terminal usando el paquete `qrcode`, ya incluido en el proyecto.
37
-
38
- > ⚠️ **Aviso importante.** Baileys es una librería no-oficial. Conectarse por esta vía viola los Términos de Servicio de WhatsApp. Para uso personal en un proyecto privado rara vez pasa nada, pero el número que uses podría ser baneado por WhatsApp en casos extremos. Se recomienda usar un **número dedicado para el bot** (eSIM, número secundario, etc.), no tu WhatsApp personal.
39
-
40
- Flujo en 5 pasos:
41
-
42
- 1. **Intro + aviso de riesgo.**
43
- 2. **Escanear QR** — el wizard dibuja el QR en la terminal. En el móvil del bot: WhatsApp → *Dispositivos Vinculados* → *Vincular un dispositivo* → escaneas.
44
- 3. **Tu número (destinatario primario)** — el número en formato E.164 (`+573001234567`) donde quieres recibir el espejo. También puedes saltar y el primer número que escriba al bot se auto-registra.
45
- 4. **Allowlist de números autorizados** — agregas los números que pueden escribirle al bot. Los mensajes de números fuera de la lista se ignoran en silencio.
46
- 5. **Iniciar bridge** — el bridge queda corriendo.
47
-
48
- Desde el panel de ejecución puedes detener el bridge, gestionar la lista de autorizados o cambiar el destinatario sin reiniciar.
49
-
50
- Comandos dentro de la CLI:
51
-
52
- ```
53
- /whatsapp # abre el wizard (alias: /wa, /whats)
54
- ```
55
-
56
- Las credenciales de sesión de WhatsApp Web se guardan como archivos en `~/.context/whatsapp-auth/` (respetando `CLAUDE_CONFIG_DIR` si está definido), porque Baileys necesita manejar ese directorio de auth. La configuracion lógica del bridge, como destinatario primario, allowlist, identidad vinculada y estado `running`, se guarda en SQLite mediante `secure_storage` en Windows/Linux.
57
-
58
- ### Configuración guardada
59
-
60
- Ambos bridges persisten su configuracion en el storage seguro. En Windows/Linux esto vive cifrado dentro de `~/.context/provider-state.sqlite3`; en macOS se mantiene el backend de keychain/fallback disponible.
61
-
62
- ```jsonc
63
- {
64
- "telegramBot": {
65
- "token": "…",
66
- "allowedUserIds": [123456],
67
- "primaryChatId": 123456,
68
- "isRunning": true
69
- },
70
- "whatsappBot": {
71
- "authDir": "~/.context/whatsapp-auth",
72
- "primaryRecipient": "+573001234567",
73
- "allowedNumbers": ["+573001234567", "+573109876543"],
74
- "selfJid": "573...@s.whatsapp.net",
75
- "selfE164": "+573...",
76
- "running": true
77
- }
78
- }
79
- ```
80
-
81
- Si existe configuracion vieja en el archivo JSON global, se migra automaticamente al leer o actualizar el bridge y se elimina esa clave legacy para evitar dos fuentes de verdad.
82
-
83
- ### Ritmo de envío
84
-
85
- Cada canal usa una cola con throttling para no dispararse contra los rate limits de la plataforma:
86
-
87
- - **Telegram:** 150 ms entre mensajes (~6 msg/s, bien por debajo del límite oficial de 30 msg/s por bot).
88
- - **WhatsApp:** 500 ms entre mensajes (más conservador — Baileys no publica límites formales y enviar demasiado rápido puede disparar shadow-bans).
89
-
90
- Si escribes prompts muy rápido la cola se llena hasta 200 items, y a partir de ahí descarta el más viejo para no crecer sin límite.
package/docs/Contex.md DELETED
@@ -1,70 +0,0 @@
1
- # Contex.md — Instrucciones para Claude
2
-
3
- ## Descripción del Proyecto
4
-
5
- Este proyecto es **Context Code** (`@context-ai/context-code`), una herramienta de línea de comandos que permite a Claude entender bases de código, editar archivos, ejecutar comandos de terminal y gestionar flujos de trabajo completos directamente desde la terminal.
6
-
7
- - **Versión actual:** 2.1.88
8
- - **Binario principal:** `context` (via `cli.js`)
9
- - **Lenguaje:** TypeScript (ES2022, módulos ESM)
10
- - **Runtime:** Node.js >= 18.0.0
11
-
12
- ## Estructura del Proyecto
13
-
14
- ```
15
- src/
16
- assistant/ # Lógica del asistente principal
17
- cli/ # Punto de entrada CLI
18
- commands/ # Definición de comandos disponibles
19
- components/ # Componentes de UI (Ink/React)
20
- context/ # Gestión del contexto de conversación
21
- coordinator/ # Coordinación de tareas y costos
22
- entrypoints/ # Puntos de entrada de la aplicación
23
- hooks/ # Hooks personalizados
24
- plugins/ # Sistema de plugins
25
- query/ # Motor de consultas (QueryEngine)
26
- screens/ # Pantallas de la interfaz
27
- services/ # Servicios externos e internos
28
- skills/ # Habilidades del agente
29
- state/ # Gestión de estado
30
- tasks/ # Sistema de tareas
31
- tools/ # Herramientas disponibles para el agente
32
- utils/ # Utilidades generales
33
- ```
34
-
35
- ## Comandos de Desarrollo
36
-
37
- ```bash
38
- pnpm typecheck # Verificar tipos TypeScript
39
- pnpm build # Compilar el proyecto
40
- pnpm dev:build # Alias de build
41
- pnpm dev:watch # Compilar en modo watch
42
- pnpm dev:run # Ejecutar versión de desarrollo
43
- pnpm start # Ejecutar la versión compilada
44
- ```
45
-
46
- ## Sistema de Proveedores
47
-
48
- El proyecto ya no debe asumirse como proveedor-unico. La capa actual distingue entre proveedor activo y perfil activo:
49
-
50
- - `provider profiles` guardan base URL, ultimo modelo y credenciales cuando aplica.
51
- - `agentName` queda reservado como nombre operativo para futuros subagentes.
52
- - los proveedores visibles ya resuelven perfiles de forma compatible; `ollama` y `zai` fueron la primera migracion completa y el resto usa fallback a la configuracion anterior.
53
- - La configuracion anterior sigue sirviendo como fallback para no romper instalaciones existentes.
54
-
55
- ## Convenciones de Código
56
-
57
- - **TypeScript estricto desactivado** (`strict: false`), pero mantener buenas prácticas de tipado.
58
- - **Módulos ESM** (`"type": "module"`), usar `import`/`export` siempre.
59
- - **Resolución de módulos:** `NodeNext` — incluir extensiones en imports cuando sea necesario.
60
- - **JSX:** `react-jsx` (usado con Ink para la UI de terminal).
61
- - **Sin comentarios innecesarios** en el código a menos que se soliciten explícitamente.
62
- - Mantener cambios **mínimos y enfocados** en la tarea solicitada.
63
- - Respetar el estilo de formato existente (indentación, espacios, etc.).
64
-
65
- ## Notas Importantes
66
-
67
- - No publicar el paquete directamente; el proceso de publicación requiere la variable de entorno `AUTHORIZED`.
68
- - `tsconfig.json` se usa para compilaciones del proyecto y `tsconfig.typecheck.json` para validación de tipos.
69
- - Los archivos de distribución se generan en `dist/`.
70
- - Consultar `RECOVERY_NOTES.md` y `RENAMING_NOTES.md` para contexto histórico del proyecto.
package/docs/LIMITS.md DELETED
@@ -1,37 +0,0 @@
1
- ## Limites y uso por proveedor
2
-
3
- `/limites` (alias `/limits`) consulta cada proveedor configurado y te muestra cuanto has consumido, cuanto te queda y los limites de tu plan, en una sola vista.
4
-
5
- ```sh
6
- /limites
7
- ```
8
-
9
- Que hace:
10
-
11
- 1. Itera sobre todos los `provider profile` que tienes guardados.
12
- 2. Para cada uno, si hay un adapter implementado, llama a su API real en paralelo (con timeout).
13
- 3. Suma a la respuesta el contador local de tokens del CLI: cuantos tokens ha consumido este perfil en la sesion actual y en el historico persistido en SQLite.
14
-
15
- Estado de cada proveedor:
16
-
17
- | Proveedor | Que se consulta |
18
- |----------------|-----------------------------------------------------------------------------------------------------------------------|
19
- | Claude (OAuth) | `GET /api/oauth/usage` -> ventanas (5h/7d/Opus/Sonnet) y extra usage. Reusa el cliente que alimenta a `/usage` |
20
- | Anthropic API | `no-data` — solo headers `anthropic-ratelimit-*` por llamada |
21
- | OpenAI OAuth | `no-data` — Codex/ChatGPT solo exponen rate limits dentro del `TokenCountEvent` de cada respuesta del modelo |
22
- | OpenAI API | `GET /v1/usage` (requiere admin key); si la key no tiene permiso, `no-data` |
23
- | OpenRouter | `GET /api/v1/auth/key` -> creditos, limite, rate limit |
24
- | MiniMax | `GET /v1/token_plan/remains` -> uso por modelo (endpoint reverse-engineered desde MiniMax-AI/cli `mmx quota show`) |
25
- | Z.AI | `GET /api/monitor/usage/quota/limit` -> tokens usados/limite del coding plan |
26
- | Ollama local | Siempre `ok` (ilimitado, corre en tu maquina); cuenta modelos disponibles |
27
- | Ollama Cloud | `no-data` salvo localhost |
28
-
29
- El contador local de tokens funciona para todos los proveedores por igual: se persiste en `~/.context/provider-state.sqlite3` y te permite saber cuanto has gastado aunque el proveedor no exponga API. La cuenta empieza en cero la primera vez que ejecutas `/limites` despues de instalar.
30
-
31
- Comandos relacionados:
32
-
33
- ```sh
34
- /limites # vista interactiva por proveedor
35
- /usage # solo Claude: limites del plan vistos por Settings
36
- /cost # costo de la sesion actual
37
- ```
@@ -1,77 +0,0 @@
1
- ## Servidores MCP externos
2
-
3
- Context Code soporta el [Model Context Protocol](https://modelcontextprotocol.io). Puedes conectar servidores MCP de terceros para dar a los agentes herramientas extra: leer una base de datos, consultar Sentry, hablar con tu wiki interna, etc.
4
-
5
- Comandos:
6
-
7
- ```sh
8
- /mcp # abre el panel de servidores configurados
9
- /mcp add <name> -- <command> [args...] # registra un servidor stdio
10
- /mcp add --transport http <name> <url> # registra un servidor HTTP
11
- /mcp add --transport sse <name> <url> # registra un servidor SSE
12
- ```
13
-
14
- Tambien puedes registrar servidores con `--scope project` (escribe en `.mcp.json` del proyecto) o `--scope user` (queda solo para tu usuario). El default es `project` cuando estas dentro de un repo y `user` cuando no.
15
-
16
- ### Ejemplo: conectar una base de datos SQLite
17
-
18
- Existen servidores MCP listos para hablar con bases de datos. El mas conocido es `mcp-server-sqlite`. Lo instalas y lo registras:
19
-
20
- ```sh
21
- # 1. Instalar el servidor (o usar npx para no instalar)
22
- pip install mcp-server-sqlite
23
-
24
- # 2. Registrarlo en Context Code apuntando a tu DB
25
- /mcp add sqlite-local -- mcp-server-sqlite --db-path ./data/app.sqlite
26
- ```
27
-
28
- A partir de ese momento, los agentes que ejecuten en este proyecto pueden listar tablas, hacer SELECT y describir el esquema sin que tu tengas que escribir SQL ni copiar/pegar resultados.
29
-
30
- ### Ejemplo: conectar Postgres
31
-
32
- ```sh
33
- # Con uvx (recomendado, sin instalacion previa)
34
- /mcp add postgres-prod --transport stdio -- uvx mcp-server-postgres \
35
- --connection-string "postgres://user:pass@localhost:5432/mydb"
36
-
37
- # O con un servidor HTTP ya desplegado
38
- /mcp add postgres-prod --transport http https://mcp.midominio.com/postgres \
39
- --header "Authorization: Bearer $TOKEN"
40
- ```
41
-
42
- Pasos a tener en cuenta:
43
-
44
- - Los servidores MCP corren con tus permisos. Si conectas a una DB de produccion, considera dar al servidor solo credenciales de lectura.
45
- - Variables sensibles: usa `-e VAR=valor` al registrar el server stdio para inyectar tokens sin que queden en el comando visible.
46
- - Las herramientas MCP aparecen en los agentes con prefijo `mcp__<name>__<tool>`. Puedes restringir cuales se autorizan con `--allowedTools` al iniciar la sesion.
47
- - Si un equipo (`database`, por ejemplo) tendria que usar este MCP, asignale un agente con `/team equipo <team> database <provider>/<agent>` y el orquestador local lo invocara cuando el plan lo requiera.
48
-
49
- ### Semble integrado
50
-
51
- Este proyecto instala y precalienta `semble` automaticamente la primera vez que arranca, y luego lo registra como MCP dinamico.
52
-
53
- Si `uv` no existe en el sistema, el CLI intenta instalarlo automaticamente en una carpeta administrada por la aplicacion y usa ese binario desde ahi.
54
-
55
- Herramientas expuestas:
56
-
57
- - `mcp__semble__search`
58
- - `mcp__semble__find_related`
59
-
60
- Bootstrap inicial:
61
-
62
- ```sh
63
- uv tool install "semble[mcp]"
64
- uv tool run --from "semble[mcp]" semble search "bootstrap" <repo> --top-k 1
65
- ```
66
-
67
- Comando MCP usado por el runtime:
68
-
69
- ```sh
70
- uv tool run --from "semble[mcp]" semble
71
- ```
72
-
73
- El primer bootstrap instala el paquete y fuerza la descarga local del modelo de embeddings que `semble` usa via Model2Vec.
74
-
75
- ### Diferencia con el storage interno
76
-
77
- El archivo `~/.context/provider-state.sqlite3` es persistencia interna del CLI (perfiles, runs, credenciales). **No es un MCP** y los agentes no lo consultan directamente; solo el runtime lo lee/escribe. Si quieres exponer datos de una base **a los agentes**, registra un servidor MCP como en los ejemplos de arriba.