@iaforged/context-code 2.2.9 → 2.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/context-bootstrap.js +8 -1
- package/contextcode-bootstrap.js +7 -1
- package/dist/src/components/ConsoleOAuthFlow.js +1 -1
- package/dist/src/components/ModelPicker.js +1 -1
- package/dist/src/utils/config.js +1 -1
- package/dist/src/utils/env.js +1 -1
- package/dist/src/utils/model/providerModels.js +1 -1
- package/dist/src/utils/permissions/filesystem.js +1 -1
- package/dist/webapp/chunk-VAB2VXFI.js +1 -1
- package/dist/webapp/main-MTQLKGXD.js +1 -1
- package/dist/webapp/ngsw.json +1 -1
- package/dist/webapp/polyfills-7R4CRVNH.js +1 -1
- package/package.json +3 -41
package/context-bootstrap.js
CHANGED
|
@@ -9,8 +9,15 @@ const __dirname = dirname(fileURLToPath(import.meta.url))
|
|
|
9
9
|
const __filename = fileURLToPath(import.meta.url)
|
|
10
10
|
const cliArgs = process.argv.slice(2)
|
|
11
11
|
|
|
12
|
+
// Context Code usa `~/.context` como home dir. Setear ambas vars: la nueva
|
|
13
|
+
// (CONTEXT_CONFIG_DIR) es la preferida; CLAUDE_CONFIG_DIR se mantiene como
|
|
14
|
+
// alias por compatibilidad con codigo heredado de upstream.
|
|
15
|
+
const ctxHome = join(homedir(), '.context')
|
|
16
|
+
if (!process.env.CONTEXT_CONFIG_DIR) {
|
|
17
|
+
process.env.CONTEXT_CONFIG_DIR = ctxHome
|
|
18
|
+
}
|
|
12
19
|
if (!process.env.CLAUDE_CONFIG_DIR) {
|
|
13
|
-
process.env.CLAUDE_CONFIG_DIR =
|
|
20
|
+
process.env.CLAUDE_CONFIG_DIR = ctxHome
|
|
14
21
|
}
|
|
15
22
|
|
|
16
23
|
// Re-spawn con heap grande si todavía no lo tenemos. V8 lee
|
package/contextcode-bootstrap.js
CHANGED
|
@@ -14,8 +14,14 @@ const __dirname = dirname(fileURLToPath(import.meta.url))
|
|
|
14
14
|
const __filename = fileURLToPath(import.meta.url)
|
|
15
15
|
const cliArgs = process.argv.slice(2)
|
|
16
16
|
|
|
17
|
+
// Setear ambas vars: CONTEXT_CONFIG_DIR es la preferida; CLAUDE_CONFIG_DIR
|
|
18
|
+
// se mantiene como alias por compatibilidad con codigo heredado.
|
|
19
|
+
const ctxHome = join(homedir(), '.context')
|
|
20
|
+
if (!process.env.CONTEXT_CONFIG_DIR) {
|
|
21
|
+
process.env.CONTEXT_CONFIG_DIR = ctxHome
|
|
22
|
+
}
|
|
17
23
|
if (!process.env.CLAUDE_CONFIG_DIR) {
|
|
18
|
-
process.env.CLAUDE_CONFIG_DIR =
|
|
24
|
+
process.env.CLAUDE_CONFIG_DIR = ctxHome
|
|
19
25
|
}
|
|
20
26
|
|
|
21
27
|
// --------------------------------------------------------------------------
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsxs as e,jsx as o,Fragment as r}from"react/jsx-runtime";import{c as i}from"react/compiler-runtime";import{useCallback as t,useEffect as n,useRef as a,useState as s}from"react";import{logEvent as l}from"../services/analytics/index.js";import{installOAuthTokens as d}from"../cli/handlers/auth.js";import{useTerminalSize as c}from"../hooks/useTerminalSize.js";import{setClipboard as u}from"../ink/termio/osc.js";import{useTerminalNotification as p}from"../ink/useTerminalNotification.js";import{Box as m,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 C}from"../services/oauth/index.js";import{getOAuthRequestDetails as y}from"../services/oauth/client.js";import{checkGeminiGoogleCredentialsValid as b,getOauthAccountInfo as A,saveGeminiGoogleOAuthTokens as k,saveProviderApiKey as P,validateForceLoginOrg as x}from"../utils/auth.js";import{startGeminiCliOAuthFlow as O}from"../services/oauth/geminiCli.js";import{ensureProviderProfile as I,isProfiledProvider as S,resolveProviderProfile as w,setActiveProviderProfile as z,setProviderProfileLastModel as D}from"../utils/model/providerProfiles.js";import{setStoredActiveProviderPreference as M,setStoredLastModelForProvider as T}from"../utils/model/providerProfilesDb.js";import{logError as j}from"../utils/log.js";import{getVisibleProvider as E}from"../utils/model/providerCatalog.js";import{getConfiguredProviderBaseUrl as R,setProviderBaseUrl as U}from"../utils/model/providerBaseUrls.js";import{getSettings_DEPRECATED as K}from"../utils/settings/settings.js";import{setCustomProviderModels as W}from"../utils/config.js";import{Select as L}from"./CustomSelect/select.js";import{KeyboardShortcutHint as G}from"./design-system/KeyboardShortcutHint.js";import{Spinner as B}from"./Spinner.js";import N from"./TextInput.js";const $=["deepseek","minimax","openrouter","zai","nvidia","ollama","openai","claudeai","gemini-google","gemini-api","console"];function sortLoginProviderOptions(e){const o=new Map($.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 F="Pega aqui el codigo si se solicita > ";function formatOAuthDebugDetails(e,o){if("openai"!==e)return"";const r=y({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:i,mode:y="login",forceLoginMethod:A,profileName:R}){const L=K()||{},B=A??L.forceLoginMethod,N=L.forceLoginOrgUUID,$="claudeai"===B?"Método de acceso preseleccionado: Plan de suscripción (Context Pro/Max)":"console"===B?"Método de acceso preseleccionado: Facturación por uso de API (Anthropic Console)":"openai"===B?"Método de acceso preseleccionado: OpenAI / Codex OAuth":null,F=p(),[V,X]=s(()=>"setup-token"===y||"claudeai"===B||"console"===B||"openai"===B?{state:"ready_to_start"}:{state:"idle"}),[Y,q]=s(""),[H,Z]=s(0),[J]=s(()=>new C),[Q,ee]=s(()=>"openai"===B?"openai":"anthropic"),[oe,re]=s(()=>"setup-token"===y||"claudeai"===B),[ie,te]=s(!1),[ne,ae]=s(!1),se=c().columns-37-1,[le,de]=s(""),[ce,ue]=s(0),[pe,me]=s(""),[he,ge]=s(0),[fe,_e]=s(""),[ve,Ce]=s(""),[ye,be]=s(""),[Ae,ke]=s(0),[Pe,xe]=s(0),[Oe,Ie]=s(0);n(()=>{"claudeai"===B?l("tengu_oauth_claudeai_forced",{}):"console"===B&&l("tengu_oauth_console_forced",{})},[B]),n(()=>{if("about_to_retry"===V.state){const e=setTimeout(X,1e3,V.nextState);return()=>clearTimeout(e)}},[V]),f("confirm:yes",()=>{l("tengu_oauth_success",{loginWithClaudeAi:oe}),r(Q)},{context:"Confirmation",isActive:"success"===V.state&&"setup-token"!==y}),n(()=>{if("success"===V.state&&!process.stdin.isTTY){const e=setTimeout(()=>{l("tengu_oauth_success",{loginWithClaudeAi:oe}),r(Q)},800);return()=>clearTimeout(e)}},[V.state,Q,oe,r]),f("confirm:yes",()=>{X({state:"idle"})},{context:"Confirmation",isActive:"platform_setup"===V.state}),f("confirm:yes",()=>{De()},{context:"Confirmation",isActive:"provider_google_setup"===V.state}),f("confirm:yes",()=>{"error"===V.state&&V.toRetry&&(q(""),X({state:"about_to_retry",nextState:V.toRetry}))},{context:"Confirmation",isActive:"error"===V.state&&!!V.toRetry}),f("cancel",()=>{X({state:"idle"})},{context:"Confirmation",isActive:"provider_api_key_input"===V.state||"provider_local_setup"===V.state||"provider_google_setup"===V.state||"error"===V.state}),n(()=>{"c"===Y&&"waiting_for_login"===V.state&&ie&&!ne&&(u(V.url).then(e=>{e&&process.stdout.write(e),ae(!0),setTimeout(ae,2e3,!1)}),q(""))},[Y,V,ie,ne]);const Se=t(async(e,o)=>{const i=e.trim();if(i)try{await P(o,i),de(""),ue(0);const e=E(o).label;v({message:`API key de ${e} guardada`,notificationType:"auth_success"},F),r(o)}catch(e){j(e),X({state:"error",message:e.message,toRetry:{state:"provider_api_key_input",provider:o}})}else X({state:"error",message:"Debes ingresar una API key.",toRetry:{state:"provider_api_key_input",provider:o}})},[r,F]),we=t((e,o)=>{const i=e.trim();if(i)try{const e=U(o,i);me(e),ge(0),v({message:`URL de ${E(o).label} guardada`,notificationType:"auth_success"},F),r(o)}catch(e){j(e),X({state:"error",message:e.message,toRetry:{state:"provider_local_setup",provider:o}})}else X({state:"error",message:"Debes ingresar una URL para Ollama.",toRetry:{state:"provider_local_setup",provider:o}})},[r,F]),ze=t((e,o)=>{const i=V;if("custom_provider_wizard"===i.state&&i.provider)if("endpoint"===e){const e=o.trim();if(e&&!e.startsWith("http"))return void X({state:"error",message:"La URL debe empezar con http:// o https://.",toRetry:i});if(!e)return void X({state:"error",message:"El endpoint es obligatorio. Ejemplo: http://localhost:8001/v1",toRetry:i});X({state:"custom_provider_wizard",provider:i.provider,step:"api_key",apiKey:i.apiKey,endpoint:e,model:i.model})}else if("api_key"===e){const e=o.trim();if(!e)return void X({state:"error",message:"La API key no puede estar vacia.",toRetry:i});X({state:"custom_provider_wizard",provider:i.provider,step:"model_list",apiKey:e,endpoint:i.endpoint,model:"",availableModels:[],modelsLoading:!0});const r=new AbortController,t=setTimeout(()=>r.abort(),15e3);fetch(`${i.endpoint}/models`,{headers:{Authorization:`Bearer ${e}`},signal:r.signal}).then(e=>e.json()).then(e=>{clearTimeout(t);const o=e.data?.map(e=>e.id)||[];X(e=>"custom_provider_wizard"!==e.state||"model_list"!==e.step?e:{...e,availableModels:o,modelsLoading:!1})}).catch(e=>{clearTimeout(t),j(e),X(e=>"custom_provider_wizard"!==e.state||"model_list"!==e.step?e:{...e,availableModels:[],modelsLoading:!1})})}else if("model"===e){const e="model_list"===i.step&&Array.isArray(i.availableModels)?i.availableModels:[];let t=null;try{if(S(i.provider))if(R&&R.trim()){const e=I(i.provider,R.trim());z(e.id),t=e.id}else t=w(i.provider,{createIfMissing:!0})?.id??null}catch(e){j(e)}P(i.provider,i.apiKey).then(()=>{U(i.provider,i.endpoint);try{M(i.provider)}catch(e){j(e)}const n=o?.trim();if(n)try{T(i.provider,n),S(i.provider)&&D(i.provider,n)}catch(e){j(e)}if(e.length>0)try{W(i.provider,e,t)}catch(e){j(e)}v({message:`Configuracion de ${E(i.provider).label} guardada`,notificationType:"auth_success"},F),r(i.provider)}).catch(e=>{j(e),X({state:"error",message:e.message,toRetry:i})})}},[r,F,V,R]),De=t(async()=>{X({state:"provider_google_auth_running"});try{if(await b())return void r("gemini-google");const e=await O();k(e);if(!await b())return v({message:"OAuth de Gemini guardado; Code Assist no valido el proyecto de cuota",notificationType:"auth_success"},F),void r("gemini-google");v({message:"Credenciales de Gemini Google listas",notificationType:"auth_success"},F),r("gemini-google")}catch(e){j(e),X({state:"error",message:e.message,toRetry:{state:"provider_google_setup"}})}},[r,F]),Me=t(async()=>{try{l("tengu_oauth_flow_start",{loginWithClaudeAi:oe,provider:Q});const e=await J.startOAuthFlow(async e=>{X({state:"waiting_for_login",url:e}),setTimeout(te,3e3,!0)},{loginWithClaudeAi:oe,provider:Q,inferenceOnly:"setup-token"===y,expiresIn:"setup-token"===y?31536e3:void 0,orgUUID:N}).catch(e=>{const o=e.message.includes("Token exchange failed"),r=_(e),i=J.getPort(),t="openai"===Q&&i?formatOAuthDebugDetails(Q,i):"";throw X({state:"error",message:r??(o?"No se pudo intercambiar el codigo de autorizacion por el token de acceso. Intentalo de nuevo."+(t?`\n${t}`:""):e.message),toRetry:"setup-token"===y?{state:"ready_to_start"}:{state:"idle"}}),l("tengu_oauth_token_exchange_error",{error:e.message,ssl_error:null!==r}),e});if("setup-token"===y)X({state:"success",token:e.accessToken});else{X({state:"creating_api_key"});const o=R?w("openai"===Q?"openai":"anthropic",R):void 0;if(await d(e,Q,o?.id),"anthropic"===Q){const e=await x();if(!e.valid)throw new Error(e.message)}X({state:"success"}),v({message:"openai"===Q?"Inicio de sesión con OpenAI / Codex completado":"Inicio de sesión en Context Code completado",notificationType:"auth_success"},F)}}catch(e){const o=e.message,r=_(e),i=J.getPort(),t="openai"===Q&&i?formatOAuthDebugDetails(Q,i):"";X({state:"error",message:r??("openai"===Q&&t&&!o.includes("redirect_uri=")?`${o}\n${t}`:o),toRetry:{state:"setup-token"===y?"ready_to_start":"idle"}}),l("tengu_oauth_error",{error:o,ssl_error:null!==r})}},[Q,J,te,oe,y,N,F]),Te=a(!1);return n(()=>{"ready_to_start"!==V.state||Te.current||(Te.current=!0,process.nextTick((e,o)=>{e(),o.current=!1},Me,Te))},[V.state,Me]),n(()=>{if("setup-token"===y&&"success"===V.state){const e=setTimeout((e,o)=>{l("tengu_oauth_success",{loginWithClaudeAi:e}),o(Q)},500,oe,r,Q);return()=>clearTimeout(e)}},[y,V,oe,r,Q]),n(()=>()=>{J.cleanup()},[J]),e(m,{flexDirection:"column",gap:1,children:["waiting_for_login"===V.state&&ie&&e(m,{flexDirection:"column",gap:1,paddingBottom:1,children:[e(m,{paddingX:1,children:[e(g,{dimColor:!0,children:["Browser didn't open? Use the url below to sign in"," "]}),o(g,ne?{color:"success",children:"(Copied!)"}:{dimColor:!0,children:o(G,{shortcut:"c",action:"copiar",parens:!0})})]}),o(h,{url:V.url,children:o(g,{dimColor:!0,children:V.url})})]},"urlToCopy"),"setup-token"===y&&"success"===V.state&&V.token&&e(m,{flexDirection:"column",gap:1,paddingTop:1,children:[o(g,{color:"success",children:"✓ Long-lived authentication token created successfully!"}),e(m,{flexDirection:"column",gap:1,children:[o(g,{children:"Your OAuth token (valid for 1 year):"}),o(g,{color:"warning",children:V.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(m,{paddingLeft:1,flexDirection:"column",gap:1,children:o(OAuthStatusMessage,{oauthStatus:V,oauthProvider:Q,mode:y,startingMessage:i,forcedMethodMessage:$,showPastePrompt:ie,pastedCode:Y,setPastedCode:q,cursorOffset:H,setCursorOffset:Z,textInputColumns:se,handleSubmitCode:async function(e,o){try{const[r,i]=e.split("#");if(!r||!i)return void X({state:"error",message:"Codigo invalido. Asegurate de copiar el codigo completo",toRetry:{state:"waiting_for_login",url:o}});l("tengu_oauth_manual_entry",{}),J.handleManualAuthCodeInput({authorizationCode:r,state:i})}catch(e){j(e),X({state:"error",message:e.message,toRetry:{state:"waiting_for_login",url:o}})}},setOAuthStatus:X,setLoginWithClaudeAi:re,setOAuthProvider:ee,providerApiKey:le,setProviderApiKey:de,providerApiKeyCursorOffset:ce,setProviderApiKeyCursorOffset:ue,handleProviderApiKeySubmit:Se,providerBaseUrl:pe,setProviderBaseUrlInput:me,providerBaseUrlCursorOffset:he,setProviderBaseUrlCursorOffset:ge,handleProviderBaseUrlSubmit:we,onDone:r,wizardApiKey:fe,setWizardApiKey:_e,wizardEndpoint:ve,setWizardEndpoint:Ce,wizardModel:ye,setWizardModel:be,wizardApiKeyCursor:Ae,setWizardApiKeyCursor:ke,wizardEndpointCursor:Pe,setWizardEndpointCursor:xe,wizardModelCursor:Oe,setWizardModelCursor:Ie,handleCustomProviderWizardSubmit:ze})})]})}function OAuthStatusMessage(t){const n=i(68),{oauthStatus:a,oauthProvider:s,mode:d,startingMessage:c,forcedMethodMessage:u,showPastePrompt:p,pastedCode:f,setPastedCode:_,cursorOffset:v,setCursorOffset:C,textInputColumns:y,handleSubmitCode:b,setOAuthStatus:k,setLoginWithClaudeAi:P,setOAuthProvider:x,providerApiKey:O,setProviderApiKey:I,providerApiKeyCursorOffset:S,setProviderApiKeyCursorOffset:w,handleProviderApiKeySubmit:z,providerBaseUrl:D,setProviderBaseUrlInput:M,providerBaseUrlCursorOffset:T,setProviderBaseUrlCursorOffset:j,handleProviderBaseUrlSubmit:U,onDone:K,wizardApiKey:W,setWizardApiKey:G,wizardEndpoint:$,setWizardEndpoint:V,wizardModel:X,setWizardModel:Y,wizardApiKeyCursor:q,setWizardApiKeyCursor:H,wizardEndpointCursor:Z,setWizardEndpointCursor:J,wizardModelCursor:Q,setWizardModelCursor:ee,handleCustomProviderWizardSubmit:oe}=t;switch(a.state){case"idle":{const r=c||"Context Code puede usarse con tu suscripción de Claude, la facturación de Anthropic Console o OpenAI / Codex OAuth.";let i,t,a,s,d,u,p;return n[0]!==r?(i=o(g,{bold:!0,children:r}),n[0]=r,n[1]=i):i=n[1],n[2]===Symbol.for("react.memo_cache_sentinel")?(t=o(g,{children:"Selecciona el metodo de acceso:"}),n[2]=t):t=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")?(d=[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"},{label:e(g,{children:["Custom OpenAI ·"," ",o(g,{dimColor:!0,children:"Wizard API key + endpoint"}),"\n"]}),value:"custom-openai"},{label:e(g,{children:["Custom Anthropic ·"," ",o(g,{dimColor:!0,children:"Wizard API key + endpoint"}),"\n"]}),value:"custom-anthropic"}],n[5]=d):d=n[5],n[6]!==P||n[7]!==k||n[8]!==x||n[65]!==K?(u=o(m,{children:o(L,{options:sortLoginProviderOptions(d),onChange:e=>{"platform"===e?(l("tengu_oauth_platform_selected",{}),k({state:"platform_setup"})):"openai"===e?(l("tengu_oauth_openai_selected",{}),x("openai"),P(!1),k({state:"ready_to_start"})):"openrouter"===e?k({state:"provider_api_key_input",provider:"openrouter"}):"gemini-api"===e||"zai"===e||"minimax"===e||"nvidia"===e||"deepseek"===e?k({state:"provider_api_key_input",provider:e}):"gemini-google"===e?k({state:"provider_google_setup"}):"ollama"===e||"ollama-cloud"===e?(M(R(e)),j(0),k({state:"provider_local_setup",provider:e})):"custom-openai"===e||"custom-anthropic"===e?k({state:"custom_provider_wizard",provider:e,step:"endpoint",apiKey:"",endpoint:"",model:""}):(x("anthropic"),k({state:"ready_to_start"}),"claudeai"===e?(l("tengu_oauth_claudeai_selected",{}),P(!0)):(l("tengu_oauth_console_selected",{}),P(!1)))}})}),n[6]=P,n[7]=k,n[8]=x,n[65]=K,n[66]=u):u=n[66],n[10]!==i||n[11]!==u?(p=e(m,{flexDirection:"column",gap:1,marginTop:1,children:[i,t,u]}),n[10]=i,n[11]=u,n[12]=p):p=n[12],p}case"provider_api_key_input":{let r,i,t,s;if(n[50]!==a.provider?(r=e(g,{bold:!0,children:["Ingresa la API key de ",E(a.provider).label]}),n[50]=a.provider,n[51]=r):r=n[51],n[52]!==a.provider){const r=E(a.provider);i=e(m,{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]=i}else i=n[53];return n[54]!==O||n[55]!==S||n[56]!==I||n[57]!==w||n[58]!==y||n[59]!==z?(t=e(m,{children:[o(g,{children:"API key > "}),o(N,{value:O,onChange:I,onSubmit:e=>z(e,a.provider),cursorOffset:S,onChangeCursorOffset:w,columns:y,mask:"*"})]}),n[54]=O,n[55]=S,n[56]=I,n[57]=w,n[58]=y,n[59]=z,n[60]=t):t=n[60],n[61]!==r||n[62]!==i||n[63]!==t?(s=e(m,{flexDirection:"column",gap:1,children:[r,i,t]}),n[61]=r,n[62]=i,n[63]=t,n[64]=s):s=n[64],s}case"provider_local_setup":{const r=E(a.provider);return e(m,{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(m,{children:o(N,{value:D,onChange:M,onSubmit:e=>U(e,a.provider),cursorOffset:T,onChangeCursorOffset:j,columns:y})}),e(g,{color:"success",children:["Presiona ",o(g,{bold:!0,children:"Enter"})," para guardar la URL y continuar."]})]})}case"provider_google_setup":return e(m,{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(m,{children:[o(B,{}),o(g,{children:"Abriendo Google OAuth para Gemini..."})]});case"custom_provider_wizard":{const r=E(a.provider),i="custom-openai"===a.provider?"https://api.openai.com/v1":"https://api.anthropic.com/v1";if("endpoint"===a.step)return e(m,{flexDirection:"column",gap:1,children:[e(g,{bold:!0,children:[r.label," - Paso 1/3"]}),o(g,{dimColor:!0,children:"URL del servidor API (ej: http://localhost:8001/v1)"}),o(g,{children:"Endpoint > "}),o(m,{children:o(N,{value:$,onChange:V,onSubmit:oe.bind(null,"endpoint"),cursorOffset:Z,onChangeCursorOffset:J,columns:y})}),e(g,{dimColor:!0,children:["Default: ",i]}),e(g,{color:"success",children:["Presiona ",o(g,{bold:!0,children:"Enter"})," para continuar."]})]});if("api_key"===a.step)return e(m,{flexDirection:"column",gap:1,children:[e(g,{bold:!0,children:[r.label," - Paso 2/3"]}),e(g,{dimColor:!0,children:["Ingresa tu API key para ",r.label,"."]}),o(g,{children:"API key > "}),o(m,{children:o(N,{value:W,onChange:G,onSubmit:oe.bind(null,"api_key"),cursorOffset:q,onChangeCursorOffset:H,columns:y,mask:"*"})}),e(g,{color:"success",children:["Presiona ",o(g,{bold:!0,children:"Enter"})," para obtener modelos disponibles."]})]});if("model_list"===a.step){if(a.modelsLoading)return e(m,{flexDirection:"column",gap:1,children:[e(g,{bold:!0,children:[r.label," - Cargando modelos..."]}),e(m,{children:[o(B,{}),e(g,{children:[" Obteniendo lista de modelos desde ",a.endpoint,"/models"]})]})]});const i=a.availableModels||[];if(i.length>0){const t=i.map(e=>({label:e,value:e}));return e(m,{flexDirection:"column",gap:1,children:[e(g,{bold:!0,children:[r.label," - Paso 3/3"]}),o(g,{dimColor:!0,children:"Selecciona un modelo de la lista:"}),o(m,{children:o(L,{options:t,onChange:e=>{k(o=>({...o,model:e})),oe("model",e)}})}),e(g,{color:"success",children:["Presiona ",o(g,{bold:!0,children:"Enter"})," para guardar la configuracion."]})]})}return e(m,{flexDirection:"column",gap:1,children:[e(g,{bold:!0,children:[r.label," - Paso 3/3"]}),o(g,{dimColor:!0,children:"No se pudo obtener la lista de modelos."}),o(g,{dimColor:!0,children:"Ingresa el nombre del modelo manualmente."}),o(g,{dimColor:!0,children:"Podras cambiarlo luego con el comando /model."}),o(g,{children:"Modelo > "}),o(m,{children:o(N,{value:X,onChange:Y,onSubmit:oe.bind(null,"model"),cursorOffset:Q,onChangeCursorOffset:ee,columns:y})}),e(g,{color:"success",children:["Presiona ",o(g,{bold:!0,children:"Enter"})," para guardar la configuracion."]})]})}break}case"platform_setup":{let r,i,t,a,s,l,d,c;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")?(i=o(g,{children:"Context Code soporta Amazon Bedrock, Microsoft Foundry y Vertex AI. Configura las variables de entorno requeridas y luego reinicia Context Code."}),t=o(g,{children:"Si formas parte de una organización empresarial, contacta a tu administrador para las instrucciones de configuración."}),n[13]=i,n[14]=t):(i=n[13],t=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")?(d=e(m,{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]=d):d=n[18],n[19]===Symbol.for("react.memo_cache_sentinel")?(c=e(m,{flexDirection:"column",gap:1,marginTop:1,children:[r,e(m,{flexDirection:"column",gap:1,children:[i,t,d,o(m,{marginTop:1,children:e(g,{dimColor:!0,children:["Presiona ",o(g,{bold:!0,children:"Enter"})," para volver a las opciones de acceso."]})})]})]}),n[19]=c):c=n[19],c}case"waiting_for_login":{let r,i,t,s;return n[20]!==u?(r=u&&o(m,{children:o(g,{dimColor:!0,children:u})}),n[20]=u,n[21]=r):r=n[21],n[22]!==p?(i=!p&&e(m,{children:[o(B,{}),o(g,{children:"Abriendo el navegador para iniciar sesión…"})]}),n[22]=p,n[23]=i):i=n[23],n[24]!==v||n[25]!==b||n[26]!==a.url||n[27]!==f||n[28]!==C||n[29]!==_||n[30]!==p||n[31]!==y?(t=p&&e(m,{children:[o(g,{children:F}),o(N,{value:f,onChange:_,onSubmit:e=>b(e,a.url),cursorOffset:v,onChangeCursorOffset:C,columns:y,mask:"*"})]}),n[24]=v,n[25]=b,n[26]=a.url,n[27]=f,n[28]=C,n[29]=_,n[30]=p,n[31]=y,n[32]=t):t=n[32],n[33]!==r||n[34]!==i||n[35]!==t?(s=e(m,{flexDirection:"column",gap:1,children:[r,i,t]}),n[33]=r,n[34]=i,n[35]=t,n[36]=s):s=n[36],s}case"creating_api_key":{let r;return n[37]===Symbol.for("react.memo_cache_sentinel")?(r=o(m,{flexDirection:"column",gap:1,children:e(m,{children:[o(B,{}),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(m,{flexDirection:"column",gap:1,children:o(g,{color:"permission",children:"Reintentando…"})}),n[38]=e):e=n[38],e}case"success":{let i,t;if(n[39]!==d||n[40]!==a.token){const t="openai"===s?"Inicio de sesión en OpenAI / Codex exitoso. Presiona ":"Inicio de sesión exitoso. Presiona ";i="setup-token"===d&&a.token?null:e(r,{children:[A()?.emailAddress?e(g,{dimColor:!0,children:["Sesión iniciada como"," ",o(g,{children:A()?.emailAddress})]}):null,e(g,{color:"success",children:[t,o(g,{bold:!0,children:"Enter"})," para continuar…"]})]}),n[39]=d,n[40]=a.token,n[41]=i}else i=n[41];return n[42]!==i?(t=o(m,{flexDirection:"column",children:i}),n[42]=i,n[43]=t):t=n[43],t}case"error":{let r,i,t;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?(i=a.toRetry&&o(m,{marginTop:1,children:e(g,{color:"permission",children:["Press ",o(g,{bold:!0,children:"Enter"})," to retry."]})}),n[46]=a.toRetry,n[47]=i):i=n[47],n[48]!==r||n[49]!==i?(t=e(m,{flexDirection:"column",gap:1,children:[r,i]}),n[48]=r,n[49]=i,n[50]=t):t=n[50],t}default:return null}}
|
|
1
|
+
import{jsxs as e,jsx as o,Fragment as r}from"react/jsx-runtime";import{c as i}from"react/compiler-runtime";import{useCallback as t,useEffect as n,useRef as a,useState as s}from"react";import{logEvent as l}from"../services/analytics/index.js";import{installOAuthTokens as d}from"../cli/handlers/auth.js";import{useTerminalSize as c}from"../hooks/useTerminalSize.js";import{setClipboard as u}from"../ink/termio/osc.js";import{useTerminalNotification as p}from"../ink/useTerminalNotification.js";import{Box as m,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 C}from"../services/oauth/index.js";import{getOAuthRequestDetails as y}from"../services/oauth/client.js";import{checkGeminiGoogleCredentialsValid as b,getOauthAccountInfo as A,saveGeminiGoogleOAuthTokens as k,saveProviderApiKey as P,validateForceLoginOrg as x}from"../utils/auth.js";import{startGeminiCliOAuthFlow as O}from"../services/oauth/geminiCli.js";import{ensureProviderProfile as I,isProfiledProvider as S,resolveProviderProfile as w,setActiveProviderProfile as z,setProviderProfileLastModel as D}from"../utils/model/providerProfiles.js";import{setStoredActiveProviderPreference as M,setStoredLastModelForProvider as T}from"../utils/model/providerProfilesDb.js";import{logError as j}from"../utils/log.js";import{getVisibleProvider as E}from"../utils/model/providerCatalog.js";import{getConfiguredProviderBaseUrl as R,setProviderBaseUrl as U}from"../utils/model/providerBaseUrls.js";import{getSettings_DEPRECATED as K}from"../utils/settings/settings.js";import{setCustomProviderModels as W}from"../utils/config.js";import{Select as L}from"./CustomSelect/select.js";import{KeyboardShortcutHint as G}from"./design-system/KeyboardShortcutHint.js";import{Spinner as B}from"./Spinner.js";import N from"./TextInput.js";const $=["deepseek","minimax","openrouter","zai","nvidia","ollama","openai","claudeai","gemini-google","gemini-api","console"];function sortLoginProviderOptions(e){const o=new Map($.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 F="Pega aqui el codigo si se solicita > ";function formatOAuthDebugDetails(e,o){if("openai"!==e)return"";const r=y({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:i,mode:y="login",forceLoginMethod:A,profileName:R}){const L=K()||{},B=A??L.forceLoginMethod,N=L.forceLoginOrgUUID,$="claudeai"===B?"Método de acceso preseleccionado: Plan de suscripción (Context Pro/Max)":"console"===B?"Método de acceso preseleccionado: Facturación por uso de API (Anthropic Console)":"openai"===B?"Método de acceso preseleccionado: OpenAI / Codex OAuth":null,F=p(),[V,X]=s(()=>"setup-token"===y||"claudeai"===B||"console"===B||"openai"===B?{state:"ready_to_start"}:{state:"idle"}),[Y,q]=s(""),[H,Z]=s(0),[J]=s(()=>new C),[Q,ee]=s(()=>"openai"===B?"openai":"anthropic"),[oe,re]=s(()=>"setup-token"===y||"claudeai"===B),[ie,te]=s(!1),[ne,ae]=s(!1),se=c().columns-37-1,[le,de]=s(""),[ce,ue]=s(0),[pe,me]=s(""),[he,ge]=s(0),[fe,_e]=s(""),[ve,Ce]=s(""),[ye,be]=s(""),[Ae,ke]=s(0),[Pe,xe]=s(0),[Oe,Ie]=s(0);n(()=>{"claudeai"===B?l("tengu_oauth_claudeai_forced",{}):"console"===B&&l("tengu_oauth_console_forced",{})},[B]),n(()=>{if("about_to_retry"===V.state){const e=setTimeout(X,1e3,V.nextState);return()=>clearTimeout(e)}},[V]),f("confirm:yes",()=>{l("tengu_oauth_success",{loginWithClaudeAi:oe}),r(Q)},{context:"Confirmation",isActive:"success"===V.state&&"setup-token"!==y}),n(()=>{if("success"===V.state&&!process.stdin.isTTY){const e=setTimeout(()=>{l("tengu_oauth_success",{loginWithClaudeAi:oe}),r(Q)},800);return()=>clearTimeout(e)}},[V.state,Q,oe,r]),f("confirm:yes",()=>{X({state:"idle"})},{context:"Confirmation",isActive:"platform_setup"===V.state}),f("confirm:yes",()=>{De()},{context:"Confirmation",isActive:"provider_google_setup"===V.state}),f("confirm:yes",()=>{"error"===V.state&&V.toRetry&&(q(""),X({state:"about_to_retry",nextState:V.toRetry}))},{context:"Confirmation",isActive:"error"===V.state&&!!V.toRetry}),f("cancel",()=>{X({state:"idle"})},{context:"Confirmation",isActive:"provider_api_key_input"===V.state||"provider_local_setup"===V.state||"provider_google_setup"===V.state||"error"===V.state}),n(()=>{"c"===Y&&"waiting_for_login"===V.state&&ie&&!ne&&(u(V.url).then(e=>{e&&process.stdout.write(e),ae(!0),setTimeout(ae,2e3,!1)}),q(""))},[Y,V,ie,ne]);const Se=t(async(e,o)=>{const i=e.trim();if(i)try{await P(o,i),de(""),ue(0);const e=E(o).label;v({message:`API key de ${e} guardada`,notificationType:"auth_success"},F),r(o)}catch(e){j(e),X({state:"error",message:e.message,toRetry:{state:"provider_api_key_input",provider:o}})}else X({state:"error",message:"Debes ingresar una API key.",toRetry:{state:"provider_api_key_input",provider:o}})},[r,F]),we=t((e,o)=>{const i=e.trim();if(i)try{const e=U(o,i);me(e),ge(0),v({message:`URL de ${E(o).label} guardada`,notificationType:"auth_success"},F),r(o)}catch(e){j(e),X({state:"error",message:e.message,toRetry:{state:"provider_local_setup",provider:o}})}else X({state:"error",message:"Debes ingresar una URL para Ollama.",toRetry:{state:"provider_local_setup",provider:o}})},[r,F]),ze=t((e,o,i)=>{const t=V;if("custom_provider_wizard"===t.state&&t.provider)if("endpoint"===e){const e=o.trim();if(e&&!e.startsWith("http"))return void X({state:"error",message:"La URL debe empezar con http:// o https://.",toRetry:t});if(!e)return void X({state:"error",message:"El endpoint es obligatorio. Ejemplo: http://localhost:8001/v1",toRetry:t});X({state:"custom_provider_wizard",provider:t.provider,step:"api_key",apiKey:t.apiKey,endpoint:e,model:t.model})}else if("api_key"===e){const e=o.trim();if(!e)return void X({state:"error",message:"La API key no puede estar vacia.",toRetry:t});X({state:"custom_provider_wizard",provider:t.provider,step:"model_list",apiKey:e,endpoint:t.endpoint,model:"",availableModels:[],modelsLoading:!0});const r=new AbortController,i=setTimeout(()=>r.abort(),15e3);fetch(`${t.endpoint}/models`,{headers:{Authorization:`Bearer ${e}`},signal:r.signal}).then(e=>e.json()).then(e=>{clearTimeout(i);const o=e.data?.map(e=>e.id)||[];X(e=>"custom_provider_wizard"!==e.state||"model_list"!==e.step?e:{...e,availableModels:o,modelsLoading:!1})}).catch(e=>{clearTimeout(i),j(e),X(e=>"custom_provider_wizard"!==e.state||"model_list"!==e.step?e:{...e,availableModels:[],modelsLoading:!1})})}else if("model"===e){const e=i&&i.length>0?i:"model_list"===t.step&&Array.isArray(t.availableModels)?t.availableModels:[];let n=null;try{if(S(t.provider))if(R&&R.trim()){const e=I(t.provider,R.trim());z(e.id),n=e.id}else n=w(t.provider,{createIfMissing:!0})?.id??null}catch(e){j(e)}P(t.provider,t.apiKey).then(()=>{U(t.provider,t.endpoint);try{M(t.provider)}catch(e){j(e)}const i=o?.trim();if(i)try{T(t.provider,i),S(t.provider)&&D(t.provider,i)}catch(e){j(e)}if(e.length>0)try{W(t.provider,e,n)}catch(e){j(e)}v({message:`Configuracion de ${E(t.provider).label} guardada`,notificationType:"auth_success"},F),r(t.provider)}).catch(e=>{j(e),X({state:"error",message:e.message,toRetry:t})})}},[r,F,V,R]),De=t(async()=>{X({state:"provider_google_auth_running"});try{if(await b())return void r("gemini-google");const e=await O();k(e);if(!await b())return v({message:"OAuth de Gemini guardado; Code Assist no valido el proyecto de cuota",notificationType:"auth_success"},F),void r("gemini-google");v({message:"Credenciales de Gemini Google listas",notificationType:"auth_success"},F),r("gemini-google")}catch(e){j(e),X({state:"error",message:e.message,toRetry:{state:"provider_google_setup"}})}},[r,F]),Me=t(async()=>{try{l("tengu_oauth_flow_start",{loginWithClaudeAi:oe,provider:Q});const e=await J.startOAuthFlow(async e=>{X({state:"waiting_for_login",url:e}),setTimeout(te,3e3,!0)},{loginWithClaudeAi:oe,provider:Q,inferenceOnly:"setup-token"===y,expiresIn:"setup-token"===y?31536e3:void 0,orgUUID:N}).catch(e=>{const o=e.message.includes("Token exchange failed"),r=_(e),i=J.getPort(),t="openai"===Q&&i?formatOAuthDebugDetails(Q,i):"";throw X({state:"error",message:r??(o?"No se pudo intercambiar el codigo de autorizacion por el token de acceso. Intentalo de nuevo."+(t?`\n${t}`:""):e.message),toRetry:"setup-token"===y?{state:"ready_to_start"}:{state:"idle"}}),l("tengu_oauth_token_exchange_error",{error:e.message,ssl_error:null!==r}),e});if("setup-token"===y)X({state:"success",token:e.accessToken});else{X({state:"creating_api_key"});const o=R?w("openai"===Q?"openai":"anthropic",R):void 0;if(await d(e,Q,o?.id),"anthropic"===Q){const e=await x();if(!e.valid)throw new Error(e.message)}X({state:"success"}),v({message:"openai"===Q?"Inicio de sesión con OpenAI / Codex completado":"Inicio de sesión en Context Code completado",notificationType:"auth_success"},F)}}catch(e){const o=e.message,r=_(e),i=J.getPort(),t="openai"===Q&&i?formatOAuthDebugDetails(Q,i):"";X({state:"error",message:r??("openai"===Q&&t&&!o.includes("redirect_uri=")?`${o}\n${t}`:o),toRetry:{state:"setup-token"===y?"ready_to_start":"idle"}}),l("tengu_oauth_error",{error:o,ssl_error:null!==r})}},[Q,J,te,oe,y,N,F]),Te=a(!1);return n(()=>{"ready_to_start"!==V.state||Te.current||(Te.current=!0,process.nextTick((e,o)=>{e(),o.current=!1},Me,Te))},[V.state,Me]),n(()=>{if("setup-token"===y&&"success"===V.state){const e=setTimeout((e,o)=>{l("tengu_oauth_success",{loginWithClaudeAi:e}),o(Q)},500,oe,r,Q);return()=>clearTimeout(e)}},[y,V,oe,r,Q]),n(()=>()=>{J.cleanup()},[J]),e(m,{flexDirection:"column",gap:1,children:["waiting_for_login"===V.state&&ie&&e(m,{flexDirection:"column",gap:1,paddingBottom:1,children:[e(m,{paddingX:1,children:[e(g,{dimColor:!0,children:["Browser didn't open? Use the url below to sign in"," "]}),o(g,ne?{color:"success",children:"(Copied!)"}:{dimColor:!0,children:o(G,{shortcut:"c",action:"copiar",parens:!0})})]}),o(h,{url:V.url,children:o(g,{dimColor:!0,children:V.url})})]},"urlToCopy"),"setup-token"===y&&"success"===V.state&&V.token&&e(m,{flexDirection:"column",gap:1,paddingTop:1,children:[o(g,{color:"success",children:"✓ Long-lived authentication token created successfully!"}),e(m,{flexDirection:"column",gap:1,children:[o(g,{children:"Your OAuth token (valid for 1 year):"}),o(g,{color:"warning",children:V.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(m,{paddingLeft:1,flexDirection:"column",gap:1,children:o(OAuthStatusMessage,{oauthStatus:V,oauthProvider:Q,mode:y,startingMessage:i,forcedMethodMessage:$,showPastePrompt:ie,pastedCode:Y,setPastedCode:q,cursorOffset:H,setCursorOffset:Z,textInputColumns:se,handleSubmitCode:async function(e,o){try{const[r,i]=e.split("#");if(!r||!i)return void X({state:"error",message:"Codigo invalido. Asegurate de copiar el codigo completo",toRetry:{state:"waiting_for_login",url:o}});l("tengu_oauth_manual_entry",{}),J.handleManualAuthCodeInput({authorizationCode:r,state:i})}catch(e){j(e),X({state:"error",message:e.message,toRetry:{state:"waiting_for_login",url:o}})}},setOAuthStatus:X,setLoginWithClaudeAi:re,setOAuthProvider:ee,providerApiKey:le,setProviderApiKey:de,providerApiKeyCursorOffset:ce,setProviderApiKeyCursorOffset:ue,handleProviderApiKeySubmit:Se,providerBaseUrl:pe,setProviderBaseUrlInput:me,providerBaseUrlCursorOffset:he,setProviderBaseUrlCursorOffset:ge,handleProviderBaseUrlSubmit:we,onDone:r,wizardApiKey:fe,setWizardApiKey:_e,wizardEndpoint:ve,setWizardEndpoint:Ce,wizardModel:ye,setWizardModel:be,wizardApiKeyCursor:Ae,setWizardApiKeyCursor:ke,wizardEndpointCursor:Pe,setWizardEndpointCursor:xe,wizardModelCursor:Oe,setWizardModelCursor:Ie,handleCustomProviderWizardSubmit:ze})})]})}function OAuthStatusMessage(t){const n=i(68),{oauthStatus:a,oauthProvider:s,mode:d,startingMessage:c,forcedMethodMessage:u,showPastePrompt:p,pastedCode:f,setPastedCode:_,cursorOffset:v,setCursorOffset:C,textInputColumns:y,handleSubmitCode:b,setOAuthStatus:k,setLoginWithClaudeAi:P,setOAuthProvider:x,providerApiKey:O,setProviderApiKey:I,providerApiKeyCursorOffset:S,setProviderApiKeyCursorOffset:w,handleProviderApiKeySubmit:z,providerBaseUrl:D,setProviderBaseUrlInput:M,providerBaseUrlCursorOffset:T,setProviderBaseUrlCursorOffset:j,handleProviderBaseUrlSubmit:U,onDone:K,wizardApiKey:W,setWizardApiKey:G,wizardEndpoint:$,setWizardEndpoint:V,wizardModel:X,setWizardModel:Y,wizardApiKeyCursor:q,setWizardApiKeyCursor:H,wizardEndpointCursor:Z,setWizardEndpointCursor:J,wizardModelCursor:Q,setWizardModelCursor:ee,handleCustomProviderWizardSubmit:oe}=t;switch(a.state){case"idle":{const r=c||"Context Code puede usarse con tu suscripción de Claude, la facturación de Anthropic Console o OpenAI / Codex OAuth.";let i,t,a,s,d,u,p;return n[0]!==r?(i=o(g,{bold:!0,children:r}),n[0]=r,n[1]=i):i=n[1],n[2]===Symbol.for("react.memo_cache_sentinel")?(t=o(g,{children:"Selecciona el metodo de acceso:"}),n[2]=t):t=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")?(d=[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"},{label:e(g,{children:["Custom OpenAI ·"," ",o(g,{dimColor:!0,children:"Wizard API key + endpoint"}),"\n"]}),value:"custom-openai"},{label:e(g,{children:["Custom Anthropic ·"," ",o(g,{dimColor:!0,children:"Wizard API key + endpoint"}),"\n"]}),value:"custom-anthropic"}],n[5]=d):d=n[5],n[6]!==P||n[7]!==k||n[8]!==x||n[65]!==K?(u=o(m,{children:o(L,{options:sortLoginProviderOptions(d),onChange:e=>{"platform"===e?(l("tengu_oauth_platform_selected",{}),k({state:"platform_setup"})):"openai"===e?(l("tengu_oauth_openai_selected",{}),x("openai"),P(!1),k({state:"ready_to_start"})):"openrouter"===e?k({state:"provider_api_key_input",provider:"openrouter"}):"gemini-api"===e||"zai"===e||"minimax"===e||"nvidia"===e||"deepseek"===e?k({state:"provider_api_key_input",provider:e}):"gemini-google"===e?k({state:"provider_google_setup"}):"ollama"===e||"ollama-cloud"===e?(M(R(e)),j(0),k({state:"provider_local_setup",provider:e})):"custom-openai"===e||"custom-anthropic"===e?k({state:"custom_provider_wizard",provider:e,step:"endpoint",apiKey:"",endpoint:"",model:""}):(x("anthropic"),k({state:"ready_to_start"}),"claudeai"===e?(l("tengu_oauth_claudeai_selected",{}),P(!0)):(l("tengu_oauth_console_selected",{}),P(!1)))}})}),n[6]=P,n[7]=k,n[8]=x,n[65]=K,n[66]=u):u=n[66],n[10]!==i||n[11]!==u?(p=e(m,{flexDirection:"column",gap:1,marginTop:1,children:[i,t,u]}),n[10]=i,n[11]=u,n[12]=p):p=n[12],p}case"provider_api_key_input":{let r,i,t,s;if(n[50]!==a.provider?(r=e(g,{bold:!0,children:["Ingresa la API key de ",E(a.provider).label]}),n[50]=a.provider,n[51]=r):r=n[51],n[52]!==a.provider){const r=E(a.provider);i=e(m,{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]=i}else i=n[53];return n[54]!==O||n[55]!==S||n[56]!==I||n[57]!==w||n[58]!==y||n[59]!==z?(t=e(m,{children:[o(g,{children:"API key > "}),o(N,{value:O,onChange:I,onSubmit:e=>z(e,a.provider),cursorOffset:S,onChangeCursorOffset:w,columns:y,mask:"*"})]}),n[54]=O,n[55]=S,n[56]=I,n[57]=w,n[58]=y,n[59]=z,n[60]=t):t=n[60],n[61]!==r||n[62]!==i||n[63]!==t?(s=e(m,{flexDirection:"column",gap:1,children:[r,i,t]}),n[61]=r,n[62]=i,n[63]=t,n[64]=s):s=n[64],s}case"provider_local_setup":{const r=E(a.provider);return e(m,{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(m,{children:o(N,{value:D,onChange:M,onSubmit:e=>U(e,a.provider),cursorOffset:T,onChangeCursorOffset:j,columns:y})}),e(g,{color:"success",children:["Presiona ",o(g,{bold:!0,children:"Enter"})," para guardar la URL y continuar."]})]})}case"provider_google_setup":return e(m,{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(m,{children:[o(B,{}),o(g,{children:"Abriendo Google OAuth para Gemini..."})]});case"custom_provider_wizard":{const r=E(a.provider),i="custom-openai"===a.provider?"https://api.openai.com/v1":"https://api.anthropic.com/v1";if("endpoint"===a.step)return e(m,{flexDirection:"column",gap:1,children:[e(g,{bold:!0,children:[r.label," - Paso 1/3"]}),o(g,{dimColor:!0,children:"URL del servidor API (ej: http://localhost:8001/v1)"}),o(g,{children:"Endpoint > "}),o(m,{children:o(N,{value:$,onChange:V,onSubmit:oe.bind(null,"endpoint"),cursorOffset:Z,onChangeCursorOffset:J,columns:y})}),e(g,{dimColor:!0,children:["Default: ",i]}),e(g,{color:"success",children:["Presiona ",o(g,{bold:!0,children:"Enter"})," para continuar."]})]});if("api_key"===a.step)return e(m,{flexDirection:"column",gap:1,children:[e(g,{bold:!0,children:[r.label," - Paso 2/3"]}),e(g,{dimColor:!0,children:["Ingresa tu API key para ",r.label,"."]}),o(g,{children:"API key > "}),o(m,{children:o(N,{value:W,onChange:G,onSubmit:oe.bind(null,"api_key"),cursorOffset:q,onChangeCursorOffset:H,columns:y,mask:"*"})}),e(g,{color:"success",children:["Presiona ",o(g,{bold:!0,children:"Enter"})," para obtener modelos disponibles."]})]});if("model_list"===a.step){if(a.modelsLoading)return e(m,{flexDirection:"column",gap:1,children:[e(g,{bold:!0,children:[r.label," - Cargando modelos..."]}),e(m,{children:[o(B,{}),e(g,{children:[" Obteniendo lista de modelos desde ",a.endpoint,"/models"]})]})]});const i=a.availableModels||[];if(i.length>0){const t=i.map(e=>({label:e,value:e}));return e(m,{flexDirection:"column",gap:1,children:[e(g,{bold:!0,children:[r.label," - Paso 3/3"]}),o(g,{dimColor:!0,children:"Selecciona un modelo de la lista:"}),o(m,{children:o(L,{options:t,onChange:e=>{k(o=>({...o,model:e})),oe("model",e,i)}})}),e(g,{color:"success",children:["Presiona ",o(g,{bold:!0,children:"Enter"})," para guardar la configuracion."]})]})}return e(m,{flexDirection:"column",gap:1,children:[e(g,{bold:!0,children:[r.label," - Paso 3/3"]}),o(g,{dimColor:!0,children:"No se pudo obtener la lista de modelos."}),o(g,{dimColor:!0,children:"Ingresa el nombre del modelo manualmente."}),o(g,{dimColor:!0,children:"Podras cambiarlo luego con el comando /model."}),o(g,{children:"Modelo > "}),o(m,{children:o(N,{value:X,onChange:Y,onSubmit:oe.bind(null,"model"),cursorOffset:Q,onChangeCursorOffset:ee,columns:y})}),e(g,{color:"success",children:["Presiona ",o(g,{bold:!0,children:"Enter"})," para guardar la configuracion."]})]})}break}case"platform_setup":{let r,i,t,a,s,l,d,c;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")?(i=o(g,{children:"Context Code soporta Amazon Bedrock, Microsoft Foundry y Vertex AI. Configura las variables de entorno requeridas y luego reinicia Context Code."}),t=o(g,{children:"Si formas parte de una organización empresarial, contacta a tu administrador para las instrucciones de configuración."}),n[13]=i,n[14]=t):(i=n[13],t=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")?(d=e(m,{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]=d):d=n[18],n[19]===Symbol.for("react.memo_cache_sentinel")?(c=e(m,{flexDirection:"column",gap:1,marginTop:1,children:[r,e(m,{flexDirection:"column",gap:1,children:[i,t,d,o(m,{marginTop:1,children:e(g,{dimColor:!0,children:["Presiona ",o(g,{bold:!0,children:"Enter"})," para volver a las opciones de acceso."]})})]})]}),n[19]=c):c=n[19],c}case"waiting_for_login":{let r,i,t,s;return n[20]!==u?(r=u&&o(m,{children:o(g,{dimColor:!0,children:u})}),n[20]=u,n[21]=r):r=n[21],n[22]!==p?(i=!p&&e(m,{children:[o(B,{}),o(g,{children:"Abriendo el navegador para iniciar sesión…"})]}),n[22]=p,n[23]=i):i=n[23],n[24]!==v||n[25]!==b||n[26]!==a.url||n[27]!==f||n[28]!==C||n[29]!==_||n[30]!==p||n[31]!==y?(t=p&&e(m,{children:[o(g,{children:F}),o(N,{value:f,onChange:_,onSubmit:e=>b(e,a.url),cursorOffset:v,onChangeCursorOffset:C,columns:y,mask:"*"})]}),n[24]=v,n[25]=b,n[26]=a.url,n[27]=f,n[28]=C,n[29]=_,n[30]=p,n[31]=y,n[32]=t):t=n[32],n[33]!==r||n[34]!==i||n[35]!==t?(s=e(m,{flexDirection:"column",gap:1,children:[r,i,t]}),n[33]=r,n[34]=i,n[35]=t,n[36]=s):s=n[36],s}case"creating_api_key":{let r;return n[37]===Symbol.for("react.memo_cache_sentinel")?(r=o(m,{flexDirection:"column",gap:1,children:e(m,{children:[o(B,{}),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(m,{flexDirection:"column",gap:1,children:o(g,{color:"permission",children:"Reintentando…"})}),n[38]=e):e=n[38],e}case"success":{let i,t;if(n[39]!==d||n[40]!==a.token){const t="openai"===s?"Inicio de sesión en OpenAI / Codex exitoso. Presiona ":"Inicio de sesión exitoso. Presiona ";i="setup-token"===d&&a.token?null:e(r,{children:[A()?.emailAddress?e(g,{dimColor:!0,children:["Sesión iniciada como"," ",o(g,{children:A()?.emailAddress})]}):null,e(g,{color:"success",children:[t,o(g,{bold:!0,children:"Enter"})," para continuar…"]})]}),n[39]=d,n[40]=a.token,n[41]=i}else i=n[41];return n[42]!==i?(t=o(m,{flexDirection:"column",children:i}),n[42]=i,n[43]=t):t=n[43],t}case"error":{let r,i,t;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?(i=a.toRetry&&o(m,{marginTop:1,children:e(g,{color:"permission",children:["Press ",o(g,{bold:!0,children:"Enter"})," to retry."]})}),n[46]=a.toRetry,n[47]=i):i=n[47],n[48]!==r||n[49]!==i?(t=e(m,{flexDirection:"column",gap:1,children:[r,i]}),n[48]=r,n[49]=i,n[50]=t):t=n[50],t}default:return null}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as e,jsxs as o,Fragment as t}from"react/jsx-runtime";import r from"lodash-es/capitalize.js";import*as i from"react";import{useMemo as n,useState as l}from"react";import{useExitOnCtrlCDWithKeybindings as a}from"../hooks/useExitOnCtrlCDWithKeybindings.js";import{logEvent as s}from"../services/analytics/index.js";import{FAST_MODE_MODEL_DISPLAY as c,isFastModeAvailable as d,isFastModeCooldown as m,isFastModeEnabled as u}from"../utils/fastMode.js";import{Box as f,Text as p,useInput as h}from"../ink.js";import{useKeybindings as v}from"../keybindings/useKeybinding.js";import{useAppState as g,useSetAppState as b}from"../state/AppState.js";import{getGlobalConfig as C,saveGlobalConfig as j}from"../utils/config.js";import{convertEffortValueToLevel as x,getDefaultEffortForModel as E,modelSupportsEffort as P,modelSupportsMaxEffort as S,resolvePickerEffortPersistence as O,toPersistableEffort as M}from"../utils/effort.js";import{getDefaultMainLoopModel as k,modelDisplayString as w,parseUserSpecifiedModel as y}from"../utils/model/model.js";import{getModelOptions as L}from"../utils/model/modelOptions.js";import{getAPIProvider as V}from"../utils/model/providers.js";import{getSettingsForSource as F,updateSettingsForSource as _}from"../utils/settings/settings.js";import{ConfigurableShortcutHint as D}from"./ConfigurableShortcutHint.js";import{Select as I}from"./CustomSelect/index.js";import{Byline as A}from"./design-system/Byline.js";import{KeyboardShortcutHint as H}from"./design-system/KeyboardShortcutHint.js";import{Pane as R}from"./design-system/Pane.js";import{effortLevelToSymbol as B}from"./EffortIndicator.js";const z="__NO_PREFERENCE__",N="__MODEL_HEADER__";function writePickerState(e){j(o=>({...o,modelPickerFavorites:e.favorites,modelPickerRecent:e.recent}))}function providerLabel(e){switch(e){case"firstParty":return"Claude";case"openai":return"OpenAI";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"minimax":return"MiniMax";case"nvidia":return"NVIDIA";default:return e}}function asSelectValue(e){return null===e?z:e}function isHeaderValue(e){return e?.startsWith(N)??!1}function resolveOptionModel(e){if(e&&!isHeaderValue(e))return e===z?k():y(e)}function getDefaultEffortLevelForOption(e){const o=resolveOptionModel(e)??k(),t=E(o);return void 0!==t?x(t):"high"}function EffortLevelIndicator({effort:o}){return e(p,{color:o?"claude":"subtle",children:B(o??"low")})}export function ModelPicker({initial:j,sessionModel:E,onSelect:k,onCancel:y,isStandaloneCommand:B,showFastModeNotice:$,headerText:G,skipSettingsWrite:K,onOpenProvider:U}){const W=b(),T=a(),Z=null===j?z:j,[q,J]=l(Z),[Q,X]=l(()=>function(){const e=C();return{favorites:e.modelPickerFavorites??[],recent:e.modelPickerRecent??[]}}()),Y=g(e=>!!u()&&e.fastMode),[ee,oe]=l(!1),te=g(e=>e.effortValue),[re,ie]=l(void 0!==te?x(te):void 0),[ne,le]=l([]);i.useEffect(()=>{(async()=>{const e=V();if("openai"===e||"openrouter"===e||"ollama"===e||"ollama-cloud"===e||"gemini-api"===e||"gemini-google"===e||"zai"===e||"minimax"===e||"nvidia"===e){const{getCachedProviderModels:o,fetchProviderModels:t}=await import("../utils/model/providerModels.js"),r=o(e);if(r)le(r);else{const o=await t(e);le(o)}}})()},[]);const ae=n(()=>L(Y??!1),[Y]),se=n(()=>{if(0===ne.length)return ae;const e=new Set;return[...ae,...ne].filter(o=>{const t=o.value??z;return!e.has(t)&&(e.add(t),!0)})},[ae,ne]),ce=n(()=>null===j||se.some(e=>e.value===j)?se:[...se,{value:j,label:w(j),description:"Modelo actual"}],[j,se]),de=n(()=>new Map(ce.map(e=>[asSelectValue(e.value),e])),[ce]),me=n(()=>{const e=ce.map(e=>asSelectValue(e.value)),o=new Set(e),t=Q.favorites.filter(e=>o.has(e)),r=Q.recent.filter(e=>e!==z&&o.has(e)&&!t.includes(e)),i=e.filter(e=>!t.includes(e)&&!r.includes(e)),n=[];if(t.length>0){n.push({value:`${N}:favorites`,label:"Favorites",disabled:!0});for(const e of t){const o=de.get(e);o&&n.push({value:e,label:`★ ${o.label}`,description:o.description})}}if(r.length>0){n.push({value:`${N}:recent`,label:"Recent",disabled:!0});for(const e of r){const o=de.get(e);o&&n.push({value:e,label:o.label,description:o.description})}}n.push({value:`${N}:provider`,label:providerLabel(V()),disabled:!0});for(const e of i){const o=de.get(e);o&&n.push({value:e,label:o.label,description:o.description})}return n},[de,ce,Q.favorites,Q.recent]),ue=n(()=>me.some(e=>e.value===Z&&!e.disabled)?Z:me.find(e=>!e.disabled)?.value,[me,Z]),fe=Math.min(10,me.length),pe=Math.max(0,me.length-fe),he=me.find(e=>e.value===q)?.label,ve=resolveOptionModel(q),ge=!!ve&&P(ve),be=!!ve&&S(ve),Ce=getDefaultEffortLevelForOption(q),je="max"!==re||be?re:"high",handleCycleEffort=e=>{ge&&(ie(o=>function(e,o,t){const r=t?["low","medium","high","max"]:["low","medium","high"],i=r.indexOf(e),n=-1!==i?i:r.indexOf("high");return"right"===o?r[(n+1)%r.length]:r[(n-1+r.length)%r.length]}(o??Ce,e,be)),oe(!0))};v({"modelPicker:decreaseEffort":()=>handleCycleEffort("left"),"modelPicker:increaseEffort":()=>handleCycleEffort("right")},{context:"ModelPicker"}),h((e,o)=>{const t=q;if(t&&!isHeaderValue(t)){if(o.ctrl&&"f"===e.toLowerCase()&&t!==z){const e=Q.favorites.includes(t)?Q.favorites.filter(e=>e!==t):[t,...Q.favorites].slice(0,25),o={...Q,favorites:e};return X(o),void writePickerState(o)}o.ctrl&&"a"===e.toLowerCase()&&U&&U()}});const xe=q&&!isHeaderValue(q)&&q!==z&&Q.favorites.includes(q)?"Unfavorite":"Favorite",Ee=o(f,{flexDirection:"column",children:[o(f,{marginBottom:1,flexDirection:"column",children:[e(p,{color:"remember",bold:!0,children:"Seleccionar modelo"}),e(p,{dimColor:!0,children:G??"Cambia entre modelos. Se aplica a esta sesion y a futuras sesiones de Context Code. Para otros nombres de modelo, usa --model."}),E&&o(p,{dimColor:!0,children:["Usando ",w(E)," en esta sesion (definido por el modo plan). Al elegir otro modelo se deshace este ajuste."]})]}),o(f,{flexDirection:"column",marginBottom:1,children:[e(I,{defaultValue:Z,defaultFocusValue:ue,options:me,onChange:e=>{if(isHeaderValue(e))return;if(s("tengu_model_command_menu_effort",{effort:re}),!K){const o=O(re,getDefaultEffortLevelForOption(e),F("userSettings")?.effortLevel,ee),t=M(o);void 0!==t&&_("userSettings",{effortLevel:t}),W(e=>({...e,effortValue:o}))}const o=ee&&ve&&P(ve)?re:void 0,t=[e,...Q.recent.filter(o=>o!==e)].slice(0,15),r={...Q,recent:t};X(r),writePickerState(r),k(function(e){return e===z?null:e}(e),o)},onFocus:e=>{J(e),ee||void 0!==te||isHeaderValue(e)||ie(getDefaultEffortLevelForOption(e))},onCancel:y??(()=>{}),visibleOptionCount:fe,hideIndexes:!0,layout:"compact-vertical"}),pe>0&&e(f,{paddingLeft:3,children:o(p,{dimColor:!0,children:["y ",pe," más…"]})})]}),e(f,{marginBottom:1,flexDirection:"column",children:o(p,ge?{dimColor:!0,children:[e(EffortLevelIndicator,{effort:je})," ",r("low"===je?"bajo":"medium"===je?"medio":"high"===je?"alto":"máximo")," ","esfuerzo",je===Ce?" (predeterminado)":""," ",e(p,{color:"subtle",children:"← → para ajustar"})]}:{color:"subtle",children:[e(EffortLevelIndicator,{effort:void 0})," Esfuerzo no soportado",he?` para ${String(he)}`:""]})}),u()?$?e(f,{marginBottom:1,children:o(p,{dimColor:!0,children:["El modo rápido está ",e(p,{bold:!0,children:"ACTIVADO"})," y disponible solo con"," ",c," (/fast). Cambiar a otros modelos desactivará el modo rápido."]})}):d()&&!m()?e(f,{marginBottom:1,children:o(p,{dimColor:!0,children:["Usa ",e(p,{bold:!0,children:"/fast"})," para activar el modo rápido (solo"," ",c,")."]})}):null:null,B&&e(p,{dimColor:!0,italic:!0,children:T.pending?o(t,{children:["Presiona ",T.keyName," de nuevo para salir"]}):o(A,{children:[e(H,{shortcut:"Enter",action:"confirmar"}),e(H,{shortcut:"Ctrl+F",action:xe}),e(H,{shortcut:"Ctrl+A",action:"Provider"}),e(D,{action:"select:cancel",context:"Seleccionar",fallback:"Esc",description:"salir"})]})})]});return B?e(R,{color:"permission",children:Ee}):Ee}
|
|
1
|
+
import{jsx as e,jsxs as o,Fragment as t}from"react/jsx-runtime";import r from"lodash-es/capitalize.js";import*as i from"react";import{useMemo as n,useState as l}from"react";import{useExitOnCtrlCDWithKeybindings as a}from"../hooks/useExitOnCtrlCDWithKeybindings.js";import{logEvent as s}from"../services/analytics/index.js";import{FAST_MODE_MODEL_DISPLAY as c,isFastModeAvailable as d,isFastModeCooldown as m,isFastModeEnabled as u}from"../utils/fastMode.js";import{Box as f,Text as p,useInput as h}from"../ink.js";import{useKeybindings as v}from"../keybindings/useKeybinding.js";import{useAppState as g,useSetAppState as b}from"../state/AppState.js";import{getGlobalConfig as C,saveGlobalConfig as j}from"../utils/config.js";import{convertEffortValueToLevel as x,getDefaultEffortForModel as E,modelSupportsEffort as P,modelSupportsMaxEffort as S,resolvePickerEffortPersistence as O,toPersistableEffort as M}from"../utils/effort.js";import{getDefaultMainLoopModel as k,modelDisplayString as w,parseUserSpecifiedModel as y}from"../utils/model/model.js";import{getModelOptions as L}from"../utils/model/modelOptions.js";import{getAPIProvider as V}from"../utils/model/providers.js";import{getSettingsForSource as F,updateSettingsForSource as _}from"../utils/settings/settings.js";import{ConfigurableShortcutHint as D}from"./ConfigurableShortcutHint.js";import{Select as I}from"./CustomSelect/index.js";import{Byline as A}from"./design-system/Byline.js";import{KeyboardShortcutHint as H}from"./design-system/KeyboardShortcutHint.js";import{Pane as R}from"./design-system/Pane.js";import{effortLevelToSymbol as B}from"./EffortIndicator.js";const z="__NO_PREFERENCE__",N="__MODEL_HEADER__";function writePickerState(e){j(o=>({...o,modelPickerFavorites:e.favorites,modelPickerRecent:e.recent}))}function providerLabel(e){switch(e){case"firstParty":return"Claude";case"openai":return"OpenAI";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"minimax":return"MiniMax";case"nvidia":return"NVIDIA";default:return e}}function asSelectValue(e){return null===e?z:e}function isHeaderValue(e){return e?.startsWith(N)??!1}function resolveOptionModel(e){if(e&&!isHeaderValue(e))return e===z?k():y(e)}function getDefaultEffortLevelForOption(e){const o=resolveOptionModel(e)??k(),t=E(o);return void 0!==t?x(t):"high"}function EffortLevelIndicator({effort:o}){return e(p,{color:o?"claude":"subtle",children:B(o??"low")})}export function ModelPicker({initial:j,sessionModel:E,onSelect:k,onCancel:y,isStandaloneCommand:B,showFastModeNotice:$,headerText:G,skipSettingsWrite:K,onOpenProvider:U}){const W=b(),T=a(),Z=null===j?z:j,[q,J]=l(Z),[Q,X]=l(()=>function(){const e=C();return{favorites:e.modelPickerFavorites??[],recent:e.modelPickerRecent??[]}}()),Y=g(e=>!!u()&&e.fastMode),[ee,oe]=l(!1),te=g(e=>e.effortValue),[re,ie]=l(void 0!==te?x(te):void 0),[ne,le]=l([]);i.useEffect(()=>{(async()=>{const e=V();if("openai"===e||"openrouter"===e||"ollama"===e||"ollama-cloud"===e||"gemini-api"===e||"gemini-google"===e||"zai"===e||"minimax"===e||"nvidia"===e||"deepseek"===e||"custom-openai"===e){const{getCachedProviderModels:o,fetchProviderModels:t}=await import("../utils/model/providerModels.js"),r=o(e);if(r)le(r);else{const o=await t(e);le(o)}}})()},[]);const ae=n(()=>L(Y??!1),[Y]),se=n(()=>{if(0===ne.length)return ae;const e=new Set;return[...ae,...ne].filter(o=>{const t=o.value??z;return!e.has(t)&&(e.add(t),!0)})},[ae,ne]),ce=n(()=>null===j||se.some(e=>e.value===j)?se:[...se,{value:j,label:w(j),description:"Modelo actual"}],[j,se]),de=n(()=>new Map(ce.map(e=>[asSelectValue(e.value),e])),[ce]),me=n(()=>{const e=ce.map(e=>asSelectValue(e.value)),o=new Set(e),t=Q.favorites.filter(e=>o.has(e)),r=Q.recent.filter(e=>e!==z&&o.has(e)&&!t.includes(e)),i=e.filter(e=>!t.includes(e)&&!r.includes(e)),n=[];if(t.length>0){n.push({value:`${N}:favorites`,label:"Favorites",disabled:!0});for(const e of t){const o=de.get(e);o&&n.push({value:e,label:`★ ${o.label}`,description:o.description})}}if(r.length>0){n.push({value:`${N}:recent`,label:"Recent",disabled:!0});for(const e of r){const o=de.get(e);o&&n.push({value:e,label:o.label,description:o.description})}}n.push({value:`${N}:provider`,label:providerLabel(V()),disabled:!0});for(const e of i){const o=de.get(e);o&&n.push({value:e,label:o.label,description:o.description})}return n},[de,ce,Q.favorites,Q.recent]),ue=n(()=>me.some(e=>e.value===Z&&!e.disabled)?Z:me.find(e=>!e.disabled)?.value,[me,Z]),fe=Math.min(10,me.length),pe=Math.max(0,me.length-fe),he=me.find(e=>e.value===q)?.label,ve=resolveOptionModel(q),ge=!!ve&&P(ve),be=!!ve&&S(ve),Ce=getDefaultEffortLevelForOption(q),je="max"!==re||be?re:"high",handleCycleEffort=e=>{ge&&(ie(o=>function(e,o,t){const r=t?["low","medium","high","max"]:["low","medium","high"],i=r.indexOf(e),n=-1!==i?i:r.indexOf("high");return"right"===o?r[(n+1)%r.length]:r[(n-1+r.length)%r.length]}(o??Ce,e,be)),oe(!0))};v({"modelPicker:decreaseEffort":()=>handleCycleEffort("left"),"modelPicker:increaseEffort":()=>handleCycleEffort("right")},{context:"ModelPicker"}),h((e,o)=>{const t=q;if(t&&!isHeaderValue(t)){if(o.ctrl&&"f"===e.toLowerCase()&&t!==z){const e=Q.favorites.includes(t)?Q.favorites.filter(e=>e!==t):[t,...Q.favorites].slice(0,25),o={...Q,favorites:e};return X(o),void writePickerState(o)}o.ctrl&&"a"===e.toLowerCase()&&U&&U()}});const xe=q&&!isHeaderValue(q)&&q!==z&&Q.favorites.includes(q)?"Unfavorite":"Favorite",Ee=o(f,{flexDirection:"column",children:[o(f,{marginBottom:1,flexDirection:"column",children:[e(p,{color:"remember",bold:!0,children:"Seleccionar modelo"}),e(p,{dimColor:!0,children:G??"Cambia entre modelos. Se aplica a esta sesion y a futuras sesiones de Context Code. Para otros nombres de modelo, usa --model."}),E&&o(p,{dimColor:!0,children:["Usando ",w(E)," en esta sesion (definido por el modo plan). Al elegir otro modelo se deshace este ajuste."]})]}),o(f,{flexDirection:"column",marginBottom:1,children:[e(I,{defaultValue:Z,defaultFocusValue:ue,options:me,onChange:e=>{if(isHeaderValue(e))return;if(s("tengu_model_command_menu_effort",{effort:re}),!K){const o=O(re,getDefaultEffortLevelForOption(e),F("userSettings")?.effortLevel,ee),t=M(o);void 0!==t&&_("userSettings",{effortLevel:t}),W(e=>({...e,effortValue:o}))}const o=ee&&ve&&P(ve)?re:void 0,t=[e,...Q.recent.filter(o=>o!==e)].slice(0,15),r={...Q,recent:t};X(r),writePickerState(r),k(function(e){return e===z?null:e}(e),o)},onFocus:e=>{J(e),ee||void 0!==te||isHeaderValue(e)||ie(getDefaultEffortLevelForOption(e))},onCancel:y??(()=>{}),visibleOptionCount:fe,hideIndexes:!0,layout:"compact-vertical"}),pe>0&&e(f,{paddingLeft:3,children:o(p,{dimColor:!0,children:["y ",pe," más…"]})})]}),e(f,{marginBottom:1,flexDirection:"column",children:o(p,ge?{dimColor:!0,children:[e(EffortLevelIndicator,{effort:je})," ",r("low"===je?"bajo":"medium"===je?"medio":"high"===je?"alto":"máximo")," ","esfuerzo",je===Ce?" (predeterminado)":""," ",e(p,{color:"subtle",children:"← → para ajustar"})]}:{color:"subtle",children:[e(EffortLevelIndicator,{effort:void 0})," Esfuerzo no soportado",he?` para ${String(he)}`:""]})}),u()?$?e(f,{marginBottom:1,children:o(p,{dimColor:!0,children:["El modo rápido está ",e(p,{bold:!0,children:"ACTIVADO"})," y disponible solo con"," ",c," (/fast). Cambiar a otros modelos desactivará el modo rápido."]})}):d()&&!m()?e(f,{marginBottom:1,children:o(p,{dimColor:!0,children:["Usa ",e(p,{bold:!0,children:"/fast"})," para activar el modo rápido (solo"," ",c,")."]})}):null:null,B&&e(p,{dimColor:!0,italic:!0,children:T.pending?o(t,{children:["Presiona ",T.keyName," de nuevo para salir"]}):o(A,{children:[e(H,{shortcut:"Enter",action:"confirmar"}),e(H,{shortcut:"Ctrl+F",action:xe}),e(H,{shortcut:"Ctrl+A",action:"Provider"}),e(D,{action:"select:cancel",context:"Seleccionar",fallback:"Esc",description:"salir"})]})})]});return B?e(R,{color:"permission",children:Ee}):Ee}
|
package/dist/src/utils/config.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{feature as e}from"../recovery/bunBundleShim.js";import{createRequire as t}from"module";const o=t(import.meta.url);import{randomBytes as r}from"crypto";import{unwatchFile as n,watchFile as s}from"fs";import i from"lodash-es/memoize.js";import a from"lodash-es/pickBy.js";import{basename as c,dirname as l,join as u,resolve as d}from"path";import{getOriginalCwd as f,getSessionTrustAccepted as p}from"../bootstrap/state.js";import{getAutoMemEntrypoint as g}from"../memdir/paths.js";import{logEvent as m}from"../services/analytics/index.js";import{getCwd as h}from"./cwd.js";import{registerCleanup as C}from"./cleanupRegistry.js";import{logForDebugging as b}from"./debug.js";import{logForDiagnosticsNoPII as y}from"./diagLogs.js";import{getGlobalClaudeFile as v}from"./env.js";import{getClaudeConfigHomeDir as E,isEnvTruthy as S}from"./envUtils.js";import{ConfigParseError as T,getErrnoCode as D}from"./errors.js";import{writeFileSyncAndFlush_DEPRECATED as _}from"./file.js";import{getFsImplementation as w}from"./fsOperations.js";import{findCanonicalGitRoot as k}from"./git.js";import{safeParseJSON as j}from"./json.js";import{stripBOM as A}from"./jsonRead.js";import*as G from"./lockfile.js";import{logError as M}from"./log.js";import{normalizePathForConfigKey as N}from"./path.js";import{getEssentialTrafficOnlyReason as U}from"./privacyLevel.js";import{getManagedFilePath as O}from"./settings/managedPath.js";const x=e("TEAMMEM")?o("../memdir/teamMemPaths.js"):null,F=e("CCR_AUTO_CONNECT")?o("../bridge/bridgeEnabled.js"):null;import{jsonParse as I,jsonStringify as P}from"./slowOperations.js";let L=!1;const R={allowedTools:[],mcpContextUris:[],mcpServers:{},enabledMcpjsonServers:[],disabledMcpjsonServers:[],hasTrustDialogAccepted:!1,projectOnboardingSeenCount:0,hasClaudeMdExternalIncludesApproved:!1,hasClaudeMdExternalIncludesWarningShown:!1};export{EDITOR_MODES,NOTIFICATION_CHANNELS}from"./configConstants.js";function createDefaultGlobalConfig(){return{numStartups:0,installMethod:void 0,autoUpdates:void 0,theme:"dark",preferredNotifChannel:"auto",verbose:!1,editorMode:"normal",autoCompactEnabled:!0,showTurnDuration:!0,hasSeenTasksHint:!1,hasUsedStash:!1,hasUsedBackgroundTask:!1,queuedCommandUpHintCount:0,diffTool:"auto",customApiKeyResponses:{approved:[],rejected:[]},env:{},tipsHistory:{},memoryUsageCount:0,promptQueueUseCount:0,btwUseCount:0,todoFeatureEnabled:!0,showExpandedTodos:!1,messageIdleNotifThresholdMs:6e4,awaySummaryBlurDelayMs:3e5,autoConnectIde:!1,autoInstallIdeExtension:!0,fileCheckpointingEnabled:!0,terminalProgressBarEnabled:!0,cachedStatsigGates:{},cachedDynamicConfigs:{},cachedGrowthBookFeatures:{},respectGitignore:!0,copyFullResponse:!1}}export const DEFAULT_GLOBAL_CONFIG={numStartups:0,installMethod:void 0,autoUpdates:void 0,theme:"dark",preferredNotifChannel:"auto",verbose:!1,editorMode:"normal",autoCompactEnabled:!0,showTurnDuration:!0,hasSeenTasksHint:!1,hasUsedStash:!1,hasUsedBackgroundTask:!1,queuedCommandUpHintCount:0,diffTool:"auto",customApiKeyResponses:{approved:[],rejected:[]},env:{},tipsHistory:{},memoryUsageCount:0,promptQueueUseCount:0,btwUseCount:0,todoFeatureEnabled:!0,showExpandedTodos:!1,messageIdleNotifThresholdMs:6e4,awaySummaryBlurDelayMs:3e5,autoConnectIde:!1,autoInstallIdeExtension:!0,fileCheckpointingEnabled:!0,terminalProgressBarEnabled:!0,cachedStatsigGates:{},cachedDynamicConfigs:{},cachedGrowthBookFeatures:{},respectGitignore:!0,copyFullResponse:!1};export const GLOBAL_CONFIG_KEYS=["apiKeyHelper","installMethod","autoUpdates","autoUpdatesProtectedForNative","theme","verbose","preferredNotifChannel","shiftEnterKeyBindingInstalled","editorMode","hasUsedBackslashReturn","autoCompactEnabled","showTurnDuration","diffTool","env","tipsHistory","todoFeatureEnabled","showExpandedTodos","messageIdleNotifThresholdMs","awaySummaryBlurDelayMs","autoConnectIde","autoInstallIdeExtension","fileCheckpointingEnabled","terminalProgressBarEnabled","showStatusInTerminalTab","taskCompleteNotifEnabled","inputNeededNotifEnabled","agentPushNotifEnabled","respectGitignore","claudeInChromeDefaultEnabled","hasCompletedContextInChromeOnboarding","lspRecommendationDisabled","lspRecommendationNeverPlugins","lspRecommendationIgnoredCount","copyFullResponse","copyOnSelect","permissionExplainerEnabled","prStatusFooterEnabled","remoteControlAtStartup","remoteDialogSeen","lastClaudeModel","lastOpenAIModel","lastOpenRouterModel","lastModelByProvider"];export function isGlobalConfigKey(e){return GLOBAL_CONFIG_KEYS.includes(e)}export const PROJECT_CONFIG_KEYS=["allowedTools","hasTrustDialogAccepted","hasCompletedProjectOnboarding"];let B=!1;export function resetTrustDialogAcceptedCacheForTesting(){B=!1}export function checkHasTrustDialogAccepted(){return B||=function(){if(p())return!0;const e=getGlobalConfig(),t=getProjectPathForConfig(),o=e.projects?.[t];if(o?.hasTrustDialogAccepted)return!0;let r=N(h());for(;;){const t=e.projects?.[r];if(t?.hasTrustDialogAccepted)return!0;const o=N(d(r,".."));if(o===r)break;r=o}return!1}()}export function isPathTrusted(e){const t=getGlobalConfig();let o=N(d(e));for(;;){if(t.projects?.[o]?.hasTrustDialogAccepted)return!0;const e=N(d(o,".."));if(e===o)return!1;o=e}}const $={...DEFAULT_GLOBAL_CONFIG,autoUpdates:!1},H={...R};export function isProjectConfigKey(e){return PROJECT_CONFIG_KEYS.includes(e)}function wouldLoseAuthState(e){const t=K.config;if(!t)return!1;const o=void 0!==t.oauthAccount&&void 0===e.oauthAccount,r=!0===t.hasCompletedOnboarding&&!0!==e.hasCompletedOnboarding;return o||r}export function saveGlobalConfig(e){if("test"===process.env.NODE_ENV){const t=e($);if(t===$)return;return void Object.assign($,t)}let t=null;try{saveConfigWithLock(v(),createDefaultGlobalConfig,o=>{const r=e(o);return r===o?o:(t={...r,projects:removeProjectHistory(o.projects)},t)})&&t&&writeThroughGlobalConfigCache(t)}catch(o){b(`Failed to save config with lock: ${o}`,{level:"error"});const r=getConfig(v(),createDefaultGlobalConfig);if(wouldLoseAuthState(r))return b("saveGlobalConfig fallback: re-read config is missing auth that cache has; refusing to write. See GH #3117.",{level:"error"}),void m("tengu_config_auth_loss_prevented",{});const n=e(r);if(n===r)return;t={...n,projects:removeProjectHistory(r.projects)},saveConfig(v(),t,DEFAULT_GLOBAL_CONFIG),writeThroughGlobalConfigCache(t)}}let K={config:null,mtime:0},W=null,z=0,V=0,Y=0;export function getGlobalConfigWriteCount(){return Y}export const CONFIG_WRITE_DISPLAY_THRESHOLD=20;function migrateConfigFields(e){if(void 0!==e.installMethod)return e;const t=e;let o="unknown",r=e.autoUpdates??!0;switch(t.autoUpdaterStatus){case"migrated":o="local";break;case"installed":o="native";break;case"disabled":r=!1;break;case"enabled":case"no_permissions":case"not_configured":o="global"}return{...e,installMethod:o,autoUpdates:r}}function removeProjectHistory(e){if(!e)return e;const t={};let o=!1;for(const[r,n]of Object.entries(e)){const e=n;if(void 0!==e.history){o=!0;const{history:n,...s}=e;t[r]=s}else t[r]=n}return o?t:e}C(async()=>{!function(){const e=z+V;e>0&&m("tengu_config_cache_stats",{cache_hits:z,cache_misses:V,hit_rate:z/e}),z=0,V=0}()});const q=1e3;let Q=!1;function writeThroughGlobalConfigCache(e){K={config:e,mtime:Date.now()},W=null}export function getGlobalConfig(){if("test"===process.env.NODE_ENV)return $;if(K.config)return z++,K.config;V++;try{let e=null;try{e=w().statSync(v())}catch{}const t=migrateConfigFields(getConfig(v(),createDefaultGlobalConfig));return K={config:t,mtime:e?.mtimeMs??Date.now()},W=e?{mtime:e.mtimeMs,size:e.size}:null,function(){if(Q||"test"===process.env.NODE_ENV)return;Q=!0;const e=v();s(e,{interval:q,persistent:!1},t=>{t.mtimeMs<=K.mtime||w().readFile(e,{encoding:"utf-8"}).then(e=>{if(t.mtimeMs<=K.mtime)return;const o=j(A(e));null!==o&&"object"==typeof o&&(K={config:migrateConfigFields({numStartups:0,installMethod:void 0,autoUpdates:void 0,theme:"dark",preferredNotifChannel:"auto",verbose:!1,editorMode:"normal",autoCompactEnabled:!0,showTurnDuration:!0,hasSeenTasksHint:!1,hasUsedStash:!1,hasUsedBackgroundTask:!1,queuedCommandUpHintCount:0,diffTool:"auto",customApiKeyResponses:{approved:[],rejected:[]},env:{},tipsHistory:{},memoryUsageCount:0,promptQueueUseCount:0,btwUseCount:0,todoFeatureEnabled:!0,showExpandedTodos:!1,messageIdleNotifThresholdMs:6e4,awaySummaryBlurDelayMs:3e5,autoConnectIde:!1,autoInstallIdeExtension:!0,fileCheckpointingEnabled:!0,terminalProgressBarEnabled:!0,cachedStatsigGates:{},cachedDynamicConfigs:{},cachedGrowthBookFeatures:{},respectGitignore:!0,copyFullResponse:!1,...o}),mtime:t.mtimeMs},W={mtime:t.mtimeMs,size:t.size})}).catch(()=>{})}),C(async()=>{n(e),Q=!1})}(),t}catch{return migrateConfigFields(getConfig(v(),createDefaultGlobalConfig))}}export function getRemoteControlAtStartup(){const t=getGlobalConfig().remoteControlAtStartup;return void 0!==t?t:!(!e("CCR_AUTO_CONNECT")||!F?.getCcrAutoConnectDefault())}export function getCustomApiKeyStatus(e){const t=getGlobalConfig();return t.customApiKeyResponses?.approved?.includes(e)?"approved":t.customApiKeyResponses?.rejected?.includes(e)?"rejected":"new"}function saveConfig(e,t,o){const r=l(e);w().mkdirSync(r);const n=a(t,(e,t)=>P(e)!==P(o[t]));_(e,P(n,null,2),{encoding:"utf-8",mode:384}),e===v()&&Y++}function saveConfigWithLock(e,t,o){const r=t(),n=l(e),s=w();let i;s.mkdirSync(n);try{const n=`${e}.lock`,l=Date.now();i=G.lockSync(e,{lockfilePath:n,onCompromised:e=>{b(`Config lock compromised: ${e}`,{level:"error"})}});const d=Date.now()-l;if(d>100&&(b("Lock acquisition took longer than expected - another Claude instance may be running"),m("tengu_config_lock_contention",{lock_time_ms:d})),W&&e===v())try{const t=s.statSync(e);t.mtimeMs===W.mtime&&t.size===W.size||m("tengu_config_stale_write",{read_mtime:W.mtime,write_mtime:t.mtimeMs,read_size:W.size,write_size:t.size})}catch(e){if("ENOENT"!==D(e))throw e}const f=getConfig(e,t);if(e===v()&&wouldLoseAuthState(f))return b("saveConfigWithLock: re-read config is missing auth that cache has; refusing to write to avoid wiping ~/.context.json. See GH #3117.",{level:"error"}),m("tengu_config_auth_loss_prevented",{}),!1;const p=o(f);if(p===f)return!1;const g=a(p,(e,t)=>P(e)!==P(r[t]));try{const t=c(e),o=getConfigBackupDir();try{s.mkdirSync(o)}catch(e){if("EEXIST"!==D(e))throw e}const r=6e4,n=s.readdirStringSync(o).filter(e=>e.startsWith(`${t}.backup.`)).sort().reverse(),i=n[0],a=i?Number(i.split(".backup.").pop()):0,l=Number.isNaN(a)||Date.now()-a>=r;if(l){const r=u(o,`${t}.backup.${Date.now()}`);s.copyFileSync(e,r)}const d=5,f=l?s.readdirStringSync(o).filter(e=>e.startsWith(`${t}.backup.`)).sort().reverse():n;for(const e of f.slice(d))try{s.unlinkSync(u(o,e))}catch{}}catch(e){"ENOENT"!==D(e)&&b(`Failed to backup config: ${e}`,{level:"error"})}return _(e,P(g,null,2),{encoding:"utf-8",mode:384}),e===v()&&Y++,!0}finally{i&&i()}}let J=!1;export function enableConfigs(){if(J)return;const e=Date.now();y("info","enable_configs_started"),J=!0,getConfig(v(),createDefaultGlobalConfig,!0),y("info","enable_configs_completed",{duration_ms:Date.now()-e})}function getConfigBackupDir(){return u(E(),"backups")}function findMostRecentBackup(e){const t=w(),o=c(e),r=getConfigBackupDir();try{const e=t.readdirStringSync(r).filter(e=>e.startsWith(`${o}.backup.`)).sort().at(-1);if(e)return u(r,e)}catch{}const n=l(e);try{const r=t.readdirStringSync(n).filter(e=>e.startsWith(`${o}.backup.`)).sort().at(-1);if(r)return u(n,r);const s=`${e}.backup`;try{return t.statSync(s),s}catch{}}catch{}return null}function getConfig(e,t,o){if(!J&&"test"!==process.env.NODE_ENV)throw new Error("Config accessed before allowed.");const r=w();try{const o=r.readFileSync(e,{encoding:"utf-8"});try{const e=I(A(o));return{...t(),...e}}catch(o){const r=o instanceof Error?o.message:String(o);throw new T(r,e,t())}}catch(n){if("ENOENT"===D(n)){const o=findMostRecentBackup(e);return o&&process.stderr.write(`\nClaude configuration file not found at: ${e}\nA backup file exists at: ${o}\nYou can manually restore it by running: cp "${o}" "${e}"\n\n`),t()}if(n instanceof T&&o)throw n;if(n instanceof T){if(b(`Config file corrupted, resetting to defaults: ${n.message}`,{level:"error"}),!L){L=!0;try{M(n);let t=!1;try{r.statSync(`${e}.backup`),t=!0}catch{}m("tengu_config_parse_error",{has_backup:t})}finally{L=!1}}process.stderr.write(`\nClaude configuration file at ${e} is corrupted: ${n.message}\n`);const t=c(e),o=getConfigBackupDir();try{r.mkdirSync(o)}catch(e){if("EEXIST"!==D(e))throw e}const s=r.readdirStringSync(o).filter(e=>e.startsWith(`${t}.corrupted.`));let i,a=!1;const l=r.readFileSync(e,{encoding:"utf-8"});for(const e of s)try{if(l===r.readFileSync(u(o,e),{encoding:"utf-8"})){a=!0;break}}catch{}if(!a){i=u(o,`${t}.corrupted.${Date.now()}`);try{r.copyFileSync(e,i),b(`Corrupted config backed up to: ${i}`,{level:"error"})}catch{}}const d=findMostRecentBackup(e);i?process.stderr.write(`The corrupted file has been backed up to: ${i}\n`):a&&process.stderr.write("The corrupted file has already been backed up.\n"),d?process.stderr.write(`A backup file exists at: ${d}\nYou can manually restore it by running: cp "${d}" "${e}"\n\n`):process.stderr.write("\n")}return t()}}export const getProjectPathForConfig=i(()=>{const e=f(),t=k(e);return N(t||d(e))});export function getCurrentProjectConfig(){if("test"===process.env.NODE_ENV)return H;const e=getProjectPathForConfig(),t=getGlobalConfig();if(!t.projects)return R;const o=t.projects[e]??R;return"string"==typeof o.allowedTools&&(o.allowedTools=j(o.allowedTools)??[]),o}export function saveCurrentProjectConfig(e){if("test"===process.env.NODE_ENV){const t=e(H);if(t===H)return;return void Object.assign(H,t)}const t=getProjectPathForConfig();let o=null;try{saveConfigWithLock(v(),createDefaultGlobalConfig,r=>{const n=r.projects?.[t]??R,s=e(n);return s===n?r:(o={...r,projects:{...r.projects,[t]:s}},o)})&&o&&writeThroughGlobalConfigCache(o)}catch(r){b(`Failed to save config with lock: ${r}`,{level:"error"});const n=getConfig(v(),createDefaultGlobalConfig);if(wouldLoseAuthState(n))return b("saveCurrentProjectConfig fallback: re-read config is missing auth that cache has; refusing to write. See GH #3117.",{level:"error"}),void m("tengu_config_auth_loss_prevented",{});const s=n.projects?.[t]??R,i=e(s);if(i===s)return;o={...n,projects:{...n.projects,[t]:i}},saveConfig(v(),o,DEFAULT_GLOBAL_CONFIG),writeThroughGlobalConfigCache(o)}}export function isAutoUpdaterDisabled(){return null!==getAutoUpdaterDisabledReason()}export function shouldSkipPluginAutoupdate(){return isAutoUpdaterDisabled()&&!S(process.env.FORCE_AUTOUPDATE_PLUGINS)}export function formatAutoUpdaterDisabledReason(e){switch(e.type){case"development":return"development build";case"env":return`${e.envVar} set`;case"config":return"config"}}export function getAutoUpdaterDisabledReason(){if("development"===process.env.NODE_ENV)return{type:"development"};if(S(process.env.DISABLE_AUTOUPDATER))return{type:"env",envVar:"DISABLE_AUTOUPDATER"};const e=U();if(e)return{type:"env",envVar:e};const t=getGlobalConfig();return!1!==t.autoUpdates||"native"===t.installMethod&&!0===t.autoUpdatesProtectedForNative?null:{type:"config"}}export function getOrCreateUserID(){const e=getGlobalConfig();if(e.userID)return e.userID;const t=r(32).toString("hex");return saveGlobalConfig(e=>({...e,userID:t})),t}export function recordFirstStartTime(){if(!getGlobalConfig().firstStartTime){const e=(new Date).toISOString();saveGlobalConfig(t=>({...t,firstStartTime:t.firstStartTime??e}))}}export function getMemoryPath(t){const o=f();switch(t){case"User":return u(E(),"CLAUDE.md");case"Local":return u(o,"CLAUDE.local.md");case"Project":return u(o,"CLAUDE.md");case"Managed":return u(O(),"CLAUDE.md");case"AutoMem":return g()}return e("TEAMMEM")?x.getTeamMemEntrypoint():""}export function getManagedClaudeRulesDir(){return u(O(),".claude","rules")}export function getUserClaudeRulesDir(){return u(E(),"rules")}function customProviderModelsCacheKey(e,t){return t&&t.trim()?t:e}export function setCustomProviderModels(e,t,o){const r=getGlobalConfig(),n={...r.customProviderModelsCache??{}};n[customProviderModelsCacheKey(e,o)]=t,saveGlobalConfig({...r,customProviderModelsCache:n})}export function getCustomProviderModels(e,t){const o=getGlobalConfig().customProviderModelsCache;if(!o)return[];const r=o[customProviderModelsCacheKey(e,t)];return r&&r.length>0?r:o[e]??[]}export const _getConfigForTesting=getConfig;export const _wouldLoseAuthStateForTesting=wouldLoseAuthState;export function _setGlobalConfigCacheForTesting(e){K.config=e,K.mtime=e?Date.now():0}
|
|
1
|
+
import{feature as e}from"../recovery/bunBundleShim.js";import{createRequire as t}from"module";const o=t(import.meta.url);import{randomBytes as r}from"crypto";import{unwatchFile as n,watchFile as s}from"fs";import i from"lodash-es/memoize.js";import a from"lodash-es/pickBy.js";import{basename as c,dirname as l,join as u,resolve as d}from"path";import{getOriginalCwd as f,getSessionTrustAccepted as p}from"../bootstrap/state.js";import{getAutoMemEntrypoint as g}from"../memdir/paths.js";import{logEvent as m}from"../services/analytics/index.js";import{getCwd as h}from"./cwd.js";import{registerCleanup as C}from"./cleanupRegistry.js";import{logForDebugging as b}from"./debug.js";import{logForDiagnosticsNoPII as y}from"./diagLogs.js";import{getGlobalClaudeFile as v}from"./env.js";import{getClaudeConfigHomeDir as E,isEnvTruthy as S}from"./envUtils.js";import{ConfigParseError as T,getErrnoCode as D}from"./errors.js";import{writeFileSyncAndFlush_DEPRECATED as _}from"./file.js";import{getFsImplementation as w}from"./fsOperations.js";import{findCanonicalGitRoot as k}from"./git.js";import{safeParseJSON as j}from"./json.js";import{stripBOM as A}from"./jsonRead.js";import*as G from"./lockfile.js";import{logError as M}from"./log.js";import{normalizePathForConfigKey as N}from"./path.js";import{getEssentialTrafficOnlyReason as U}from"./privacyLevel.js";import{getManagedFilePath as O}from"./settings/managedPath.js";const x=e("TEAMMEM")?o("../memdir/teamMemPaths.js"):null,F=e("CCR_AUTO_CONNECT")?o("../bridge/bridgeEnabled.js"):null;import{jsonParse as I,jsonStringify as P}from"./slowOperations.js";let L=!1;const R={allowedTools:[],mcpContextUris:[],mcpServers:{},enabledMcpjsonServers:[],disabledMcpjsonServers:[],hasTrustDialogAccepted:!1,projectOnboardingSeenCount:0,hasClaudeMdExternalIncludesApproved:!1,hasClaudeMdExternalIncludesWarningShown:!1};export{EDITOR_MODES,NOTIFICATION_CHANNELS}from"./configConstants.js";function createDefaultGlobalConfig(){return{numStartups:0,installMethod:void 0,autoUpdates:void 0,theme:"dark",preferredNotifChannel:"auto",verbose:!1,editorMode:"normal",autoCompactEnabled:!0,showTurnDuration:!0,hasSeenTasksHint:!1,hasUsedStash:!1,hasUsedBackgroundTask:!1,queuedCommandUpHintCount:0,diffTool:"auto",customApiKeyResponses:{approved:[],rejected:[]},env:{},tipsHistory:{},memoryUsageCount:0,promptQueueUseCount:0,btwUseCount:0,todoFeatureEnabled:!0,showExpandedTodos:!1,messageIdleNotifThresholdMs:6e4,awaySummaryBlurDelayMs:3e5,autoConnectIde:!1,autoInstallIdeExtension:!0,fileCheckpointingEnabled:!0,terminalProgressBarEnabled:!0,cachedStatsigGates:{},cachedDynamicConfigs:{},cachedGrowthBookFeatures:{},respectGitignore:!0,copyFullResponse:!1}}export const DEFAULT_GLOBAL_CONFIG={numStartups:0,installMethod:void 0,autoUpdates:void 0,theme:"dark",preferredNotifChannel:"auto",verbose:!1,editorMode:"normal",autoCompactEnabled:!0,showTurnDuration:!0,hasSeenTasksHint:!1,hasUsedStash:!1,hasUsedBackgroundTask:!1,queuedCommandUpHintCount:0,diffTool:"auto",customApiKeyResponses:{approved:[],rejected:[]},env:{},tipsHistory:{},memoryUsageCount:0,promptQueueUseCount:0,btwUseCount:0,todoFeatureEnabled:!0,showExpandedTodos:!1,messageIdleNotifThresholdMs:6e4,awaySummaryBlurDelayMs:3e5,autoConnectIde:!1,autoInstallIdeExtension:!0,fileCheckpointingEnabled:!0,terminalProgressBarEnabled:!0,cachedStatsigGates:{},cachedDynamicConfigs:{},cachedGrowthBookFeatures:{},respectGitignore:!0,copyFullResponse:!1};export const GLOBAL_CONFIG_KEYS=["apiKeyHelper","installMethod","autoUpdates","autoUpdatesProtectedForNative","theme","verbose","preferredNotifChannel","shiftEnterKeyBindingInstalled","editorMode","hasUsedBackslashReturn","autoCompactEnabled","showTurnDuration","diffTool","env","tipsHistory","todoFeatureEnabled","showExpandedTodos","messageIdleNotifThresholdMs","awaySummaryBlurDelayMs","autoConnectIde","autoInstallIdeExtension","fileCheckpointingEnabled","terminalProgressBarEnabled","showStatusInTerminalTab","taskCompleteNotifEnabled","inputNeededNotifEnabled","agentPushNotifEnabled","respectGitignore","claudeInChromeDefaultEnabled","hasCompletedContextInChromeOnboarding","lspRecommendationDisabled","lspRecommendationNeverPlugins","lspRecommendationIgnoredCount","copyFullResponse","copyOnSelect","permissionExplainerEnabled","prStatusFooterEnabled","remoteControlAtStartup","remoteDialogSeen","lastClaudeModel","lastOpenAIModel","lastOpenRouterModel","lastModelByProvider"];export function isGlobalConfigKey(e){return GLOBAL_CONFIG_KEYS.includes(e)}export const PROJECT_CONFIG_KEYS=["allowedTools","hasTrustDialogAccepted","hasCompletedProjectOnboarding"];let B=!1;export function resetTrustDialogAcceptedCacheForTesting(){B=!1}export function checkHasTrustDialogAccepted(){return B||=function(){if(p())return!0;const e=getGlobalConfig(),t=getProjectPathForConfig(),o=e.projects?.[t];if(o?.hasTrustDialogAccepted)return!0;let r=N(h());for(;;){const t=e.projects?.[r];if(t?.hasTrustDialogAccepted)return!0;const o=N(d(r,".."));if(o===r)break;r=o}return!1}()}export function isPathTrusted(e){const t=getGlobalConfig();let o=N(d(e));for(;;){if(t.projects?.[o]?.hasTrustDialogAccepted)return!0;const e=N(d(o,".."));if(e===o)return!1;o=e}}const $={...DEFAULT_GLOBAL_CONFIG,autoUpdates:!1},H={...R};export function isProjectConfigKey(e){return PROJECT_CONFIG_KEYS.includes(e)}function wouldLoseAuthState(e){const t=K.config;if(!t)return!1;const o=void 0!==t.oauthAccount&&void 0===e.oauthAccount,r=!0===t.hasCompletedOnboarding&&!0!==e.hasCompletedOnboarding;return o||r}export function saveGlobalConfig(e){if("test"===process.env.NODE_ENV){const t=e($);if(t===$)return;return void Object.assign($,t)}let t=null;try{saveConfigWithLock(v(),createDefaultGlobalConfig,o=>{const r=e(o);return r===o?o:(t={...r,projects:removeProjectHistory(o.projects)},t)})&&t&&writeThroughGlobalConfigCache(t)}catch(o){b(`Failed to save config with lock: ${o}`,{level:"error"});const r=getConfig(v(),createDefaultGlobalConfig);if(wouldLoseAuthState(r))return b("saveGlobalConfig fallback: re-read config is missing auth that cache has; refusing to write. See GH #3117.",{level:"error"}),void m("tengu_config_auth_loss_prevented",{});const n=e(r);if(n===r)return;t={...n,projects:removeProjectHistory(r.projects)},saveConfig(v(),t,DEFAULT_GLOBAL_CONFIG),writeThroughGlobalConfigCache(t)}}let K={config:null,mtime:0},W=null,z=0,V=0,Y=0;export function getGlobalConfigWriteCount(){return Y}export const CONFIG_WRITE_DISPLAY_THRESHOLD=20;function migrateConfigFields(e){if(void 0!==e.installMethod)return e;const t=e;let o="unknown",r=e.autoUpdates??!0;switch(t.autoUpdaterStatus){case"migrated":o="local";break;case"installed":o="native";break;case"disabled":r=!1;break;case"enabled":case"no_permissions":case"not_configured":o="global"}return{...e,installMethod:o,autoUpdates:r}}function removeProjectHistory(e){if(!e)return e;const t={};let o=!1;for(const[r,n]of Object.entries(e)){const e=n;if(void 0!==e.history){o=!0;const{history:n,...s}=e;t[r]=s}else t[r]=n}return o?t:e}C(async()=>{!function(){const e=z+V;e>0&&m("tengu_config_cache_stats",{cache_hits:z,cache_misses:V,hit_rate:z/e}),z=0,V=0}()});const q=1e3;let Q=!1;function writeThroughGlobalConfigCache(e){K={config:e,mtime:Date.now()},W=null}export function getGlobalConfig(){if("test"===process.env.NODE_ENV)return $;if(K.config)return z++,K.config;V++;try{let e=null;try{e=w().statSync(v())}catch{}const t=migrateConfigFields(getConfig(v(),createDefaultGlobalConfig));return K={config:t,mtime:e?.mtimeMs??Date.now()},W=e?{mtime:e.mtimeMs,size:e.size}:null,function(){if(Q||"test"===process.env.NODE_ENV)return;Q=!0;const e=v();s(e,{interval:q,persistent:!1},t=>{t.mtimeMs<=K.mtime||w().readFile(e,{encoding:"utf-8"}).then(e=>{if(t.mtimeMs<=K.mtime)return;const o=j(A(e));null!==o&&"object"==typeof o&&(K={config:migrateConfigFields({numStartups:0,installMethod:void 0,autoUpdates:void 0,theme:"dark",preferredNotifChannel:"auto",verbose:!1,editorMode:"normal",autoCompactEnabled:!0,showTurnDuration:!0,hasSeenTasksHint:!1,hasUsedStash:!1,hasUsedBackgroundTask:!1,queuedCommandUpHintCount:0,diffTool:"auto",customApiKeyResponses:{approved:[],rejected:[]},env:{},tipsHistory:{},memoryUsageCount:0,promptQueueUseCount:0,btwUseCount:0,todoFeatureEnabled:!0,showExpandedTodos:!1,messageIdleNotifThresholdMs:6e4,awaySummaryBlurDelayMs:3e5,autoConnectIde:!1,autoInstallIdeExtension:!0,fileCheckpointingEnabled:!0,terminalProgressBarEnabled:!0,cachedStatsigGates:{},cachedDynamicConfigs:{},cachedGrowthBookFeatures:{},respectGitignore:!0,copyFullResponse:!1,...o}),mtime:t.mtimeMs},W={mtime:t.mtimeMs,size:t.size})}).catch(()=>{})}),C(async()=>{n(e),Q=!1})}(),t}catch{return migrateConfigFields(getConfig(v(),createDefaultGlobalConfig))}}export function getRemoteControlAtStartup(){const t=getGlobalConfig().remoteControlAtStartup;return void 0!==t?t:!(!e("CCR_AUTO_CONNECT")||!F?.getCcrAutoConnectDefault())}export function getCustomApiKeyStatus(e){const t=getGlobalConfig();return t.customApiKeyResponses?.approved?.includes(e)?"approved":t.customApiKeyResponses?.rejected?.includes(e)?"rejected":"new"}function saveConfig(e,t,o){const r=l(e);w().mkdirSync(r);const n=a(t,(e,t)=>P(e)!==P(o[t]));_(e,P(n,null,2),{encoding:"utf-8",mode:384}),e===v()&&Y++}function saveConfigWithLock(e,t,o){const r=t(),n=l(e),s=w();let i;s.mkdirSync(n);try{const n=`${e}.lock`,l=Date.now();i=G.lockSync(e,{lockfilePath:n,onCompromised:e=>{b(`Config lock compromised: ${e}`,{level:"error"})}});const d=Date.now()-l;if(d>100&&(b("Lock acquisition took longer than expected - another Claude instance may be running"),m("tengu_config_lock_contention",{lock_time_ms:d})),W&&e===v())try{const t=s.statSync(e);t.mtimeMs===W.mtime&&t.size===W.size||m("tengu_config_stale_write",{read_mtime:W.mtime,write_mtime:t.mtimeMs,read_size:W.size,write_size:t.size})}catch(e){if("ENOENT"!==D(e))throw e}const f=getConfig(e,t);if(e===v()&&wouldLoseAuthState(f))return b("saveConfigWithLock: re-read config is missing auth that cache has; refusing to write to avoid wiping ~/.context.json. See GH #3117.",{level:"error"}),m("tengu_config_auth_loss_prevented",{}),!1;const p=o(f);if(p===f)return!1;const g=a(p,(e,t)=>P(e)!==P(r[t]));try{const t=c(e),o=getConfigBackupDir();try{s.mkdirSync(o)}catch(e){if("EEXIST"!==D(e))throw e}const r=6e4,n=s.readdirStringSync(o).filter(e=>e.startsWith(`${t}.backup.`)).sort().reverse(),i=n[0],a=i?Number(i.split(".backup.").pop()):0,l=Number.isNaN(a)||Date.now()-a>=r;if(l){const r=u(o,`${t}.backup.${Date.now()}`);s.copyFileSync(e,r)}const d=5,f=l?s.readdirStringSync(o).filter(e=>e.startsWith(`${t}.backup.`)).sort().reverse():n;for(const e of f.slice(d))try{s.unlinkSync(u(o,e))}catch{}}catch(e){"ENOENT"!==D(e)&&b(`Failed to backup config: ${e}`,{level:"error"})}return _(e,P(g,null,2),{encoding:"utf-8",mode:384}),e===v()&&Y++,!0}finally{i&&i()}}let J=!1;export function enableConfigs(){if(J)return;const e=Date.now();y("info","enable_configs_started"),J=!0,getConfig(v(),createDefaultGlobalConfig,!0),y("info","enable_configs_completed",{duration_ms:Date.now()-e})}function getConfigBackupDir(){return u(E(),"backups")}function findMostRecentBackup(e){const t=w(),o=c(e),r=getConfigBackupDir();try{const e=t.readdirStringSync(r).filter(e=>e.startsWith(`${o}.backup.`)).sort().at(-1);if(e)return u(r,e)}catch{}const n=l(e);try{const r=t.readdirStringSync(n).filter(e=>e.startsWith(`${o}.backup.`)).sort().at(-1);if(r)return u(n,r);const s=`${e}.backup`;try{return t.statSync(s),s}catch{}}catch{}return null}function getConfig(e,t,o){if(!J&&"test"!==process.env.NODE_ENV)throw new Error("Config accessed before allowed.");const r=w();try{const o=r.readFileSync(e,{encoding:"utf-8"});try{const e=I(A(o));return{...t(),...e}}catch(o){const r=o instanceof Error?o.message:String(o);throw new T(r,e,t())}}catch(n){if("ENOENT"===D(n)){const o=findMostRecentBackup(e);return o&&process.stderr.write(`\nClaude configuration file not found at: ${e}\nA backup file exists at: ${o}\nYou can manually restore it by running: cp "${o}" "${e}"\n\n`),t()}if(n instanceof T&&o)throw n;if(n instanceof T){if(b(`Config file corrupted, resetting to defaults: ${n.message}`,{level:"error"}),!L){L=!0;try{M(n);let t=!1;try{r.statSync(`${e}.backup`),t=!0}catch{}m("tengu_config_parse_error",{has_backup:t})}finally{L=!1}}process.stderr.write(`\nClaude configuration file at ${e} is corrupted: ${n.message}\n`);const t=c(e),o=getConfigBackupDir();try{r.mkdirSync(o)}catch(e){if("EEXIST"!==D(e))throw e}const s=r.readdirStringSync(o).filter(e=>e.startsWith(`${t}.corrupted.`));let i,a=!1;const l=r.readFileSync(e,{encoding:"utf-8"});for(const e of s)try{if(l===r.readFileSync(u(o,e),{encoding:"utf-8"})){a=!0;break}}catch{}if(!a){i=u(o,`${t}.corrupted.${Date.now()}`);try{r.copyFileSync(e,i),b(`Corrupted config backed up to: ${i}`,{level:"error"})}catch{}}const d=findMostRecentBackup(e);i?process.stderr.write(`The corrupted file has been backed up to: ${i}\n`):a&&process.stderr.write("The corrupted file has already been backed up.\n"),d?process.stderr.write(`A backup file exists at: ${d}\nYou can manually restore it by running: cp "${d}" "${e}"\n\n`):process.stderr.write("\n")}return t()}}export const getProjectPathForConfig=i(()=>{const e=f(),t=k(e);return N(t||d(e))});export function getCurrentProjectConfig(){if("test"===process.env.NODE_ENV)return H;const e=getProjectPathForConfig(),t=getGlobalConfig();if(!t.projects)return R;const o=t.projects[e]??R;return"string"==typeof o.allowedTools&&(o.allowedTools=j(o.allowedTools)??[]),o}export function saveCurrentProjectConfig(e){if("test"===process.env.NODE_ENV){const t=e(H);if(t===H)return;return void Object.assign(H,t)}const t=getProjectPathForConfig();let o=null;try{saveConfigWithLock(v(),createDefaultGlobalConfig,r=>{const n=r.projects?.[t]??R,s=e(n);return s===n?r:(o={...r,projects:{...r.projects,[t]:s}},o)})&&o&&writeThroughGlobalConfigCache(o)}catch(r){b(`Failed to save config with lock: ${r}`,{level:"error"});const n=getConfig(v(),createDefaultGlobalConfig);if(wouldLoseAuthState(n))return b("saveCurrentProjectConfig fallback: re-read config is missing auth that cache has; refusing to write. See GH #3117.",{level:"error"}),void m("tengu_config_auth_loss_prevented",{});const s=n.projects?.[t]??R,i=e(s);if(i===s)return;o={...n,projects:{...n.projects,[t]:i}},saveConfig(v(),o,DEFAULT_GLOBAL_CONFIG),writeThroughGlobalConfigCache(o)}}export function isAutoUpdaterDisabled(){return null!==getAutoUpdaterDisabledReason()}export function shouldSkipPluginAutoupdate(){return isAutoUpdaterDisabled()&&!S(process.env.FORCE_AUTOUPDATE_PLUGINS)}export function formatAutoUpdaterDisabledReason(e){switch(e.type){case"development":return"development build";case"env":return`${e.envVar} set`;case"config":return"config"}}export function getAutoUpdaterDisabledReason(){if("development"===process.env.NODE_ENV)return{type:"development"};if(S(process.env.DISABLE_AUTOUPDATER))return{type:"env",envVar:"DISABLE_AUTOUPDATER"};const e=U();if(e)return{type:"env",envVar:e};const t=getGlobalConfig();return!1!==t.autoUpdates||"native"===t.installMethod&&!0===t.autoUpdatesProtectedForNative?null:{type:"config"}}export function getOrCreateUserID(){const e=getGlobalConfig();if(e.userID)return e.userID;const t=r(32).toString("hex");return saveGlobalConfig(e=>({...e,userID:t})),t}export function recordFirstStartTime(){if(!getGlobalConfig().firstStartTime){const e=(new Date).toISOString();saveGlobalConfig(t=>({...t,firstStartTime:t.firstStartTime??e}))}}export function getMemoryPath(t){const o=f();switch(t){case"User":return u(E(),"CLAUDE.md");case"Local":return u(o,"CLAUDE.local.md");case"Project":return u(o,"CLAUDE.md");case"Managed":return u(O(),"CLAUDE.md");case"AutoMem":return g()}return e("TEAMMEM")?x.getTeamMemEntrypoint():""}export function getManagedClaudeRulesDir(){return u(O(),".claude","rules")}export function getUserClaudeRulesDir(){return u(E(),"rules")}function customProviderModelsCacheKey(e,t){return t&&t.trim()?t:e}export function setCustomProviderModels(e,t,o){const r=getGlobalConfig(),n={...r.customProviderModelsCache??{}};n[customProviderModelsCacheKey(e,o)]=t,o&&o.trim()&&(n[e]=t),saveGlobalConfig({...r,customProviderModelsCache:n})}export function getCustomProviderModels(e,t){const o=getGlobalConfig().customProviderModelsCache;if(!o)return[];const r=o[customProviderModelsCacheKey(e,t)];return r&&r.length>0?r:o[e]??[]}export const _getConfigForTesting=getConfig;export const _wouldLoseAuthStateForTesting=wouldLoseAuthState;export function _setGlobalConfigCacheForTesting(e){K.config=e,K.mtime=e?Date.now():0}
|
package/dist/src/utils/env.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import e from"lodash-es/memoize.js";import{
|
|
1
|
+
import e from"lodash-es/memoize.js";import{join as r}from"path";import{fileSuffixForOauthConfig as n}from"../constants/oauth.js";import{isRunningWithBun as s}from"./bundledMode.js";import{getClaudeConfigHomeDir as t,isEnvTruthy as i}from"./envUtils.js";import{findExecutable as o}from"./findExecutable.js";import{getFsImplementation as c}from"./fsOperations.js";import{which as u}from"./which.js";export const getGlobalClaudeFile=e(()=>{const e=c(),s=process.env.CONTEXT_CONFIG_DIR||process.env.CLAUDE_CONFIG_DIR||t(),i=n(),o=r(s,`.context${i}.json`);if(e.existsSync(o))return o;const u=r(s,`.claude${i}.json`);if(e.existsSync(u))return u;const a=r(s,".config.json");return e.existsSync(a)?a:o});const a=e(async()=>{try{const{default:e}=await import("axios");return await e.head("http://1.1.1.1",{signal:AbortSignal.timeout(1e3)}),!0}catch{return!1}});async function isCommandAvailable(e){try{return!!await u(e)}catch{return!1}}const p=e(async()=>{const e=[];return await isCommandAvailable("npm")&&e.push("npm"),await isCommandAvailable("yarn")&&e.push("yarn"),await isCommandAvailable("pnpm")&&e.push("pnpm"),e}),E=e(async()=>{const e=[];return await isCommandAvailable("bun")&&e.push("bun"),await isCommandAvailable("deno")&&e.push("deno"),await isCommandAvailable("node")&&e.push("node"),e}),f=e(()=>{try{return c().existsSync("/proc/sys/fs/binfmt_misc/WSLInterop")}catch(e){return!1}}),v=e(()=>{try{if(!f())return!1;const{cmd:e}=o("npm",[]);return e.startsWith("/mnt/c/")}catch(e){return!1}});export const JETBRAINS_IDES=["pycharm","intellij","webstorm","phpstorm","rubymine","clion","goland","rider","datagrip","appcode","dataspell","aqua","gateway","fleet","jetbrains","androidstudio"];export const detectDeploymentEnvironment=e(()=>{if(i(process.env.CODESPACES))return"codespaces";if(process.env.GITPOD_WORKSPACE_ID)return"gitpod";if(process.env.REPL_ID||process.env.REPL_SLUG)return"replit";if(process.env.PROJECT_DOMAIN)return"glitch";if(i(process.env.VERCEL))return"vercel";if(process.env.RAILWAY_ENVIRONMENT_NAME||process.env.RAILWAY_SERVICE_NAME)return"railway";if(i(process.env.RENDER))return"render";if(i(process.env.NETLIFY))return"netlify";if(process.env.DYNO)return"heroku";if(process.env.FLY_APP_NAME||process.env.FLY_MACHINE_ID)return"fly.io";if(i(process.env.CF_PAGES))return"cloudflare-pages";if(process.env.DENO_DEPLOYMENT_ID)return"deno-deploy";if(process.env.AWS_LAMBDA_FUNCTION_NAME)return"aws-lambda";if("AWS_ECS_FARGATE"===process.env.AWS_EXECUTION_ENV)return"aws-fargate";if("AWS_ECS_EC2"===process.env.AWS_EXECUTION_ENV)return"aws-ecs";try{if(c().readFileSync("/sys/hypervisor/uuid",{encoding:"utf8"}).trim().toLowerCase().startsWith("ec2"))return"aws-ec2"}catch{}if(process.env.K_SERVICE)return"gcp-cloud-run";if(process.env.GOOGLE_CLOUD_PROJECT)return"gcp";if(process.env.WEBSITE_SITE_NAME||process.env.WEBSITE_SKU)return"azure-app-service";if(process.env.AZURE_FUNCTIONS_ENVIRONMENT)return"azure-functions";if(process.env.APP_URL?.includes("ondigitalocean.app"))return"digitalocean-app-platform";if(process.env.SPACE_CREATOR_USER_ID)return"huggingface-spaces";if(i(process.env.GITHUB_ACTIONS))return"github-actions";if(i(process.env.GITLAB_CI))return"gitlab-ci";if(process.env.CIRCLECI)return"circleci";if(process.env.BUILDKITE)return"buildkite";if(i(process.env.CI))return"ci";if(process.env.KUBERNETES_SERVICE_HOST)return"kubernetes";try{if(c().existsSync("/.dockerenv"))return"docker"}catch{}return"darwin"===env.platform?"unknown-darwin":"linux"===env.platform?"unknown-linux":"win32"===env.platform?"unknown-win32":"unknown"});function isSSHSession(){return!!(process.env.SSH_CONNECTION||process.env.SSH_CLIENT||process.env.SSH_TTY)}export const env={hasInternetAccess:a,isCI:i(process.env.CI),platform:["win32","darwin"].includes(process.platform)?process.platform:"linux",arch:process.arch,nodeVersion:process.version,terminal:function(){if(process.env.CURSOR_TRACE_ID)return"cursor";if(process.env.VSCODE_GIT_ASKPASS_MAIN?.includes("cursor"))return"cursor";if(process.env.VSCODE_GIT_ASKPASS_MAIN?.includes("windsurf"))return"windsurf";if(process.env.VSCODE_GIT_ASKPASS_MAIN?.includes("antigravity"))return"antigravity";const e=process.env.__CFBundleIdentifier?.toLowerCase();if(e?.includes("vscodium"))return"codium";if(e?.includes("windsurf"))return"windsurf";if(e?.includes("com.google.android.studio"))return"androidstudio";if(e)for(const r of JETBRAINS_IDES)if(e.includes(r))return r;if(process.env.VisualStudioVersion)return"visualstudio";if("JetBrains-JediTerm"===process.env.TERMINAL_EMULATOR)return process.platform,"pycharm";if("xterm-ghostty"===process.env.TERM)return"ghostty";if(process.env.TERM?.includes("kitty"))return"kitty";if(process.env.TERM_PROGRAM)return process.env.TERM_PROGRAM;if(process.env.TMUX)return"tmux";if(process.env.STY)return"screen";if(process.env.KONSOLE_VERSION)return"konsole";if(process.env.GNOME_TERMINAL_SERVICE)return"gnome-terminal";if(process.env.XTERM_VERSION)return"xterm";if(process.env.VTE_VERSION)return"vte-based";if(process.env.TERMINATOR_UUID)return"terminator";if(process.env.KITTY_WINDOW_ID)return"kitty";if(process.env.ALACRITTY_LOG)return"alacritty";if(process.env.TILIX_ID)return"tilix";if(process.env.WT_SESSION)return"windows-terminal";if(process.env.SESSIONNAME&&"cygwin"===process.env.TERM)return"cygwin";if(process.env.MSYSTEM)return process.env.MSYSTEM.toLowerCase();if(process.env.ConEmuANSI||process.env.ConEmuPID||process.env.ConEmuTask)return"conemu";if(process.env.WSL_DISTRO_NAME)return`wsl-${process.env.WSL_DISTRO_NAME}`;if(isSSHSession())return"ssh-session";if(process.env.TERM){const e=process.env.TERM;return e.includes("alacritty")?"alacritty":e.includes("rxvt")?"rxvt":e.includes("termite")?"termite":process.env.TERM}return process.stdout.isTTY?null:"non-interactive"}(),isSSH:isSSHSession,getPackageManagers:p,getRuntimes:E,isRunningWithBun:e(s),isWslEnvironment:f,isNpmFromWindowsPath:v,isConductor:function(){return"com.conductor.app"===process.env.__CFBundleIdentifier},detectDeploymentEnvironment};export function getHostPlatformForAnalytics(){const e=process.env.CONTEXT_CODE_HOST_PLATFORM??process.env.CLAUDE_CODE_HOST_PLATFORM;return"win32"===e||"darwin"===e||"linux"===e?e:env.platform}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{getGeminiGoogleAuthHeaders as e,getMiniMaxAccessToken as a,getOpenAICompatibleAccessToken as i}from"../auth.js";import{getConfiguredProviderBaseUrl as t}from"./providerBaseUrls.js";import{getResolvedProviderProfileId as r,isProfiledProvider as o}from"./providerProfiles.js";const n={"minimax-m2.7":"Modelo de razonamiento general y chat predeterminado.","minimax-m2.7-highspeed":"Version rapida de MiniMax-M2.7.","minimax-m2.5":"Modelo de razonamiento avanzado con alta capacidad.","minimax-m2.5-highspeed":"Version rapida de MiniMax-M2.5.","minimax-m2.1":"Optimizado para programacion y desarrollo.","minimax-m2.1-highspeed":"Version rapida de MiniMax-M2.1.","minimax-m2":"Capacidades agenciales y razonamiento avanzado."},l=["MiniMax-M2.7","MiniMax-M2.7-highspeed","MiniMax-M2.5","MiniMax-M2.5-highspeed","MiniMax-M2.1","MiniMax-M2.1-highspeed","MiniMax-M2"].map(e=>({value:e,label:e,description:n[e.toLowerCase()]??""})),s=[{value:"deepseek-v4-pro",label:"DeepSeek V4 Pro",description:"Familia V4 pro — razonamiento profundo y código. Contexto 1M tokens."},{value:"deepseek-v4-flash",label:"DeepSeek V4 Flash",description:"Familia V4 flash — alto volumen, baja latencia. Contexto 1M tokens."},{value:"deepseek-chat",label:"deepseek-chat",description:"Alias estable V3 (api.deepseek.com). Contexto 128k tokens."},{value:"deepseek-reasoner",label:"deepseek-reasoner",description:"Alias estable R1/V3 con chain-of-thought. Contexto 128k tokens."}],c=[{value:"gemini-3.5-pro",label:"Gemini 3.5 Pro",description:"Modelo Gemini principal para razonamiento, codigo y agentes."},{value:"gemini-3.5-flash",label:"Gemini 3.5 Flash",description:"Modelo Gemini rapido con capacidades multimodales y de codigo."},{value:"gemini-3.5-flash-lite",label:"Gemini 3.5 Flash-Lite",description:"Variante de bajo costo y baja latencia."},{value:"gemini-3.1-pro-preview",label:"Gemini 3.1 Pro Preview",description:"Version anterior de Pro."},{value:"gemini-3-flash-preview",label:"Gemini 3 Flash Preview",description:"Version anterior de Flash."},{value:"gemini-3.1-flash-lite-preview",label:"Gemini 3.1 Flash-Lite Preview",description:"Version anterior de Flash-Lite."},{value:"gemini-2.5-pro",label:"Gemini 2.5 Pro",description:"Modelo estable para razonamiento y codigo."},{value:"gemini-2.5-flash",label:"Gemini 2.5 Flash",description:"Modelo estable rapido para alto volumen."},{value:"gemini-2.5-flash-lite",label:"Gemini 2.5 Flash-Lite",description:"Modelo estable economico y de baja latencia."}],d=new Map,u=new Map;function trimTrailingSlash(e){return e.endsWith("/")?e.slice(0,-1):e}function ensureV1Suffix(e){const a=trimTrailingSlash(e);return a.endsWith("/v1")?a:`${a}/v1`}function isLocalOllamaProviderHost(e){try{const a=new URL(e);return"localhost"===a.hostname||"127.0.0.1"===a.hostname}catch{return e.includes("localhost")||e.includes("127.0.0.1")}}function getProviderCacheKey(e){const a=getProviderBaseUrl(e);return`${e}:${(o(e)?r(e):null)??"default"}:${a}`}function getProviderLabel(e){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"minimax":return"MiniMax";case"nvidia":return"NVIDIA NIM";case"deepseek":return"DeepSeek";default:return"OpenAI"}}function getProviderBaseUrl(e){switch(e){case"openrouter":return ensureV1Suffix(process.env.OPENROUTER_BASE_URL||t("openrouter")||"https://openrouter.ai/api/v1");case"ollama":return ensureV1Suffix(process.env.OLLAMA_BASE_URL||t("ollama")||"http://localhost:11434/v1");case"ollama-cloud":return ensureV1Suffix(process.env.OLLAMA_CLOUD_BASE_URL||process.env.OLLAMA_BASE_URL||t("ollama-cloud")||"http://localhost:11434/v1");case"zai":return trimTrailingSlash(process.env.ZAI_BASE_URL||t("zai")||"https://api.z.ai/api/coding/paas/v4");case"gemini-api":return trimTrailingSlash(process.env.GEMINI_BASE_URL||process.env.GEMINI_API_BASE_URL||t("gemini-api")||"https://generativelanguage.googleapis.com/v1beta/openai");case"gemini-google":return trimTrailingSlash(process.env.GEMINI_GOOGLE_BASE_URL||process.env.GEMINI_BASE_URL||t("gemini-google")||"https://generativelanguage.googleapis.com/v1beta/openai");case"minimax":return trimTrailingSlash(process.env.MINIMAX_BASE_URL||t("minimax")||"https://api.minimax.io/anthropic");case"nvidia":return ensureV1Suffix(process.env.NVIDIA_BASE_URL||t("nvidia")||"https://integrate.api.nvidia.com/v1");case"deepseek":return ensureV1Suffix(process.env.DEEPSEEK_BASE_URL||t("deepseek")||"https://api.deepseek.com/v1");default:return ensureV1Suffix(process.env.OPENAI_API_BASE_URL||process.env.OPENAI_BASE_URL||"https://api.openai.com/v1")}}async function buildProviderHeaders(a){if("gemini-google"===a)return e();const t={},r=i(a),o=getProviderBaseUrl(a);return"ollama"!==a&&!("ollama-cloud"===a&&isLocalOllamaProviderHost(o))&&r&&(t.Authorization=`Bearer ${r}`),"openrouter"===a&&(t["HTTP-Referer"]="https://context.iaforged.com",t["X-Title"]="Context Code"),t}function formatOpenAICompatibleDescription(e){const a=[];return e.description&&a.push(e.description),e.context_length&&a.push(`Context: ${e.context_length}`),(e.pricing?.prompt||e.pricing?.completion)&&a.push(`Price: ${e.pricing?.prompt??"?"} prompt / ${e.pricing?.completion??"?"} completion`),a.join(" · ")}function mapOpenAICompatibleModels(e,a){return(e.data??[]).map(e=>{const i=e.id?.trim();if(!i)return null;const t="minimax"===a?n[i.toLowerCase()]:void 0;return{value:i,label:e.name?.trim()||i,description:formatOpenAICompatibleDescription(e)||t||""}}).filter(e=>null!==e)}function filterOllamaModels(e,a,i){return"ollama-cloud"===e&&isLocalOllamaProviderHost(i)?a.filter(e=>e.value.toLowerCase().endsWith(":cloud")):a}async function fetchJson(e,a){const i=await fetch(e,{headers:a});if(!i.ok)throw new Error(`Failed to load models from ${e}: ${i.status}`);return i.json()}function cacheProviderHealth(e){return u.set(getProviderCacheKey(e.provider),{expiresAt:Date.now()+3e4,result:e}),e}function buildHealthResult(e,a,i,t={}){return{provider:e,label:getProviderLabel(e),state:a,message:i,baseUrl:t.baseUrl??getProviderBaseUrl(e),statusCode:t.statusCode,checkedAt:Date.now()}}async function fetchWithTimeout(e,a,i=5e3){const t=new AbortController,r=setTimeout(()=>t.abort(),i);try{return await fetch(e,{headers:a,signal:t.signal})}finally{clearTimeout(r)}}export async function checkProviderHealth(e,t={}){if(!t.forceRefresh){const a=function(e){const a=u.get(getProviderCacheKey(e));return a?a.expiresAt<Date.now()?(u.delete(getProviderCacheKey(e)),null):a.result:null}(e);if(a)return a}const r=getProviderBaseUrl(e),o=getProviderLabel(e),n="minimax"===e?{"x-api-key":a()??"",Authorization:`Bearer ${a()??""}`,"Content-Type":"application/json"}:await buildProviderHeaders(e),l="minimax"===e?a():i(e);if(!("ollama"===e||"gemini-google"===e||"ollama-cloud"===e&&isLocalOllamaProviderHost(r)||l))return cacheProviderHealth(buildHealthResult(e,"needs-setup",`${o} no tiene credenciales configuradas.`,{baseUrl:r}));try{if("minimax"===e)return cacheProviderHealth(buildHealthResult(e,"healthy",`${o} configurado para Anthropic-compatible (${r}).`,{baseUrl:r}));if("ollama"===e||"ollama-cloud"===e){const a=[`${r.endsWith("/v1")?r.slice(0,-3):r}/api/tags`,`${r}/models`];let i,t="";for(const o of a){const a=await fetchWithTimeout(o,n);if(a.ok)return cacheProviderHealth(buildHealthResult(e,"healthy",`Conectado a ${o}.`,{baseUrl:r,statusCode:a.status}));if(i=a.status,t=`${a.status} ${a.statusText}`.trim(),404!==a.status||!o.endsWith("/api/tags"))break}return cacheProviderHealth(429===i?buildHealthResult(e,"rate-limited",`${o} devolvió rate limit al validar la conexión.`,{baseUrl:r,statusCode:i}):buildHealthResult(e,"unreachable",t?`${o} no respondió correctamente (${t}).`:`${o} no respondió correctamente.`,{baseUrl:r,statusCode:i}))}const a=`${r}/models`,i=await fetchWithTimeout(a,n);return i.ok?cacheProviderHealth(buildHealthResult(e,"healthy",`Conectado a ${a}.`,{baseUrl:r,statusCode:i.status})):401===i.status||403===i.status?cacheProviderHealth(buildHealthResult(e,"needs-setup",`${o} rechazó la solicitud. Revisa la API key o token configurado.`,{baseUrl:r,statusCode:i.status})):429===i.status?cacheProviderHealth(buildHealthResult(e,"rate-limited",`${o} devolvió rate limit al validar la conexión.`,{baseUrl:r,statusCode:i.status})):cacheProviderHealth(buildHealthResult(e,"unreachable",`${o} respondió con ${i.status} al validar la conexión.`,{baseUrl:r,statusCode:i.status}))}catch(a){const i=function(e){return e instanceof Error?e.message.replace(/\s+/g," ").trim():String(e).replace(/\s+/g," ").trim()}(a);return"ollama"===e&&(i.toLowerCase().includes("econnrefused")||i.toLowerCase().includes("fetch failed")||i.toLowerCase().includes("networkerror")||i.toLowerCase().includes("localhost:11434"))?cacheProviderHealth(buildHealthResult(e,"unreachable","Ollama no es accesible. Inicia el servidor local o revisa OLLAMA_BASE_URL.",{baseUrl:r})):i.includes("401")||i.includes("403")||i.toLowerCase().includes("authentication")?cacheProviderHealth(buildHealthResult(e,"needs-setup",`${o} no tiene credenciales válidas.`,{baseUrl:r})):i.includes("429")||i.toLowerCase().includes("rate limit")?cacheProviderHealth(buildHealthResult(e,"rate-limited",`${o} devolvió rate limit al validar la conexión.`,{baseUrl:r})):cacheProviderHealth(buildHealthResult(e,"unreachable",`${o} no pudo validarse: ${i||"error desconocido"}.`,{baseUrl:r}))}}export function getCachedProviderModels(e){return d.get(getProviderCacheKey(e))??null}export async function fetchProviderModels(e){const a=getProviderCacheKey(e),i=d.get(a);if(i)return i;try{if("minimax"===e)return d.set(a,l),l;if("deepseek"===e)return d.set(a,s),s;let i=[];if("ollama"===e||"ollama-cloud"===e){const a=getProviderBaseUrl(e),t=a.endsWith("/v1")?a.slice(0,-3):a;try{i=filterOllamaModels(e,function(e){return(e.models??[]).map(e=>{const a=e.model?.trim()||e.name?.trim();if(!a)return null;const i=[e.details?.family,e.details?.parameter_size,e.details?.quantization_level].filter(Boolean);return{value:a,label:e.name?.trim()||a,description:i.join(" · ")}}).filter(e=>null!==e)}(await fetchJson(`${t}/api/tags`,await buildProviderHeaders(e))),a)}catch{i=filterOllamaModels(e,mapOpenAICompatibleModels(await fetchJson(`${a}/models`,await buildProviderHeaders(e)),e),a)}}else{i=mapOpenAICompatibleModels(await fetchJson(`${getProviderBaseUrl(e)}/models`,await buildProviderHeaders(e)),e)}if("gemini-api"===e||"gemini-google"===e){const e=new Set(c.map(e=>e.value));i=[...c,...i.filter(a=>!e.has(a.value))]}return d.set(a,i),i}catch{return"gemini-api"===e||"gemini-google"===e?(d.set(a,c),c):[]}}
|
|
1
|
+
import{getGeminiGoogleAuthHeaders as e,getMiniMaxAccessToken as a,getOpenAICompatibleAccessToken as i}from"../auth.js";import{getConfiguredProviderBaseUrl as t}from"./providerBaseUrls.js";import{getResolvedProviderProfileId as r,isProfiledProvider as o}from"./providerProfiles.js";const n={"minimax-m2.7":"Modelo de razonamiento general y chat predeterminado.","minimax-m2.7-highspeed":"Version rapida de MiniMax-M2.7.","minimax-m2.5":"Modelo de razonamiento avanzado con alta capacidad.","minimax-m2.5-highspeed":"Version rapida de MiniMax-M2.5.","minimax-m2.1":"Optimizado para programacion y desarrollo.","minimax-m2.1-highspeed":"Version rapida de MiniMax-M2.1.","minimax-m2":"Capacidades agenciales y razonamiento avanzado."},l=["MiniMax-M2.7","MiniMax-M2.7-highspeed","MiniMax-M2.5","MiniMax-M2.5-highspeed","MiniMax-M2.1","MiniMax-M2.1-highspeed","MiniMax-M2"].map(e=>({value:e,label:e,description:n[e.toLowerCase()]??""})),s=[{value:"deepseek-v4-pro",label:"DeepSeek V4 Pro",description:"Familia V4 pro — razonamiento profundo y código. Contexto 1M tokens."},{value:"deepseek-v4-flash",label:"DeepSeek V4 Flash",description:"Familia V4 flash — alto volumen, baja latencia. Contexto 1M tokens."},{value:"deepseek-chat",label:"deepseek-chat",description:"Alias estable V3 (api.deepseek.com). Contexto 128k tokens."},{value:"deepseek-reasoner",label:"deepseek-reasoner",description:"Alias estable R1/V3 con chain-of-thought. Contexto 128k tokens."}],c=[{value:"gemini-3.5-pro",label:"Gemini 3.5 Pro",description:"Modelo Gemini principal para razonamiento, codigo y agentes."},{value:"gemini-3.5-flash",label:"Gemini 3.5 Flash",description:"Modelo Gemini rapido con capacidades multimodales y de codigo."},{value:"gemini-3.5-flash-lite",label:"Gemini 3.5 Flash-Lite",description:"Variante de bajo costo y baja latencia."},{value:"gemini-3.1-pro-preview",label:"Gemini 3.1 Pro Preview",description:"Version anterior de Pro."},{value:"gemini-3-flash-preview",label:"Gemini 3 Flash Preview",description:"Version anterior de Flash."},{value:"gemini-3.1-flash-lite-preview",label:"Gemini 3.1 Flash-Lite Preview",description:"Version anterior de Flash-Lite."},{value:"gemini-2.5-pro",label:"Gemini 2.5 Pro",description:"Modelo estable para razonamiento y codigo."},{value:"gemini-2.5-flash",label:"Gemini 2.5 Flash",description:"Modelo estable rapido para alto volumen."},{value:"gemini-2.5-flash-lite",label:"Gemini 2.5 Flash-Lite",description:"Modelo estable economico y de baja latencia."}],d=new Map,u=new Map;function trimTrailingSlash(e){return e.endsWith("/")?e.slice(0,-1):e}function ensureV1Suffix(e){const a=trimTrailingSlash(e);return a.endsWith("/v1")?a:`${a}/v1`}function isLocalOllamaProviderHost(e){try{const a=new URL(e);return"localhost"===a.hostname||"127.0.0.1"===a.hostname}catch{return e.includes("localhost")||e.includes("127.0.0.1")}}function getProviderCacheKey(e){const a=getProviderBaseUrl(e);return`${e}:${(o(e)?r(e):null)??"default"}:${a}`}function getProviderLabel(e){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"minimax":return"MiniMax";case"nvidia":return"NVIDIA NIM";case"deepseek":return"DeepSeek";default:return"OpenAI"}}function getProviderBaseUrl(e){switch(e){case"openrouter":return ensureV1Suffix(process.env.OPENROUTER_BASE_URL||t("openrouter")||"https://openrouter.ai/api/v1");case"ollama":return ensureV1Suffix(process.env.OLLAMA_BASE_URL||t("ollama")||"http://localhost:11434/v1");case"ollama-cloud":return ensureV1Suffix(process.env.OLLAMA_CLOUD_BASE_URL||process.env.OLLAMA_BASE_URL||t("ollama-cloud")||"http://localhost:11434/v1");case"zai":return trimTrailingSlash(process.env.ZAI_BASE_URL||t("zai")||"https://api.z.ai/api/coding/paas/v4");case"gemini-api":return trimTrailingSlash(process.env.GEMINI_BASE_URL||process.env.GEMINI_API_BASE_URL||t("gemini-api")||"https://generativelanguage.googleapis.com/v1beta/openai");case"gemini-google":return trimTrailingSlash(process.env.GEMINI_GOOGLE_BASE_URL||process.env.GEMINI_BASE_URL||t("gemini-google")||"https://generativelanguage.googleapis.com/v1beta/openai");case"minimax":return trimTrailingSlash(process.env.MINIMAX_BASE_URL||t("minimax")||"https://api.minimax.io/anthropic");case"nvidia":return ensureV1Suffix(process.env.NVIDIA_BASE_URL||t("nvidia")||"https://integrate.api.nvidia.com/v1");case"deepseek":return ensureV1Suffix(process.env.DEEPSEEK_BASE_URL||t("deepseek")||"https://api.deepseek.com/v1");case"custom-openai":return ensureV1Suffix(t("custom-openai")||"https://api.openai.com/v1");default:return ensureV1Suffix(process.env.OPENAI_API_BASE_URL||process.env.OPENAI_BASE_URL||"https://api.openai.com/v1")}}async function buildProviderHeaders(a){if("gemini-google"===a)return e();const t={},r=i(a),o=getProviderBaseUrl(a);return"ollama"!==a&&!("ollama-cloud"===a&&isLocalOllamaProviderHost(o))&&r&&(t.Authorization=`Bearer ${r}`),"openrouter"===a&&(t["HTTP-Referer"]="https://context.iaforged.com",t["X-Title"]="Context Code"),t}function formatOpenAICompatibleDescription(e){const a=[];return e.description&&a.push(e.description),e.context_length&&a.push(`Context: ${e.context_length}`),(e.pricing?.prompt||e.pricing?.completion)&&a.push(`Price: ${e.pricing?.prompt??"?"} prompt / ${e.pricing?.completion??"?"} completion`),a.join(" · ")}function mapOpenAICompatibleModels(e,a){return(e.data??[]).map(e=>{const i=e.id?.trim();if(!i)return null;const t="minimax"===a?n[i.toLowerCase()]:void 0;return{value:i,label:e.name?.trim()||i,description:formatOpenAICompatibleDescription(e)||t||""}}).filter(e=>null!==e)}function filterOllamaModels(e,a,i){return"ollama-cloud"===e&&isLocalOllamaProviderHost(i)?a.filter(e=>e.value.toLowerCase().endsWith(":cloud")):a}async function fetchJson(e,a){const i=await fetch(e,{headers:a});if(!i.ok)throw new Error(`Failed to load models from ${e}: ${i.status}`);return i.json()}function cacheProviderHealth(e){return u.set(getProviderCacheKey(e.provider),{expiresAt:Date.now()+3e4,result:e}),e}function buildHealthResult(e,a,i,t={}){return{provider:e,label:getProviderLabel(e),state:a,message:i,baseUrl:t.baseUrl??getProviderBaseUrl(e),statusCode:t.statusCode,checkedAt:Date.now()}}async function fetchWithTimeout(e,a,i=5e3){const t=new AbortController,r=setTimeout(()=>t.abort(),i);try{return await fetch(e,{headers:a,signal:t.signal})}finally{clearTimeout(r)}}export async function checkProviderHealth(e,t={}){if(!t.forceRefresh){const a=function(e){const a=u.get(getProviderCacheKey(e));return a?a.expiresAt<Date.now()?(u.delete(getProviderCacheKey(e)),null):a.result:null}(e);if(a)return a}const r=getProviderBaseUrl(e),o=getProviderLabel(e),n="minimax"===e?{"x-api-key":a()??"",Authorization:`Bearer ${a()??""}`,"Content-Type":"application/json"}:await buildProviderHeaders(e),l="minimax"===e?a():i(e);if(!("ollama"===e||"gemini-google"===e||"ollama-cloud"===e&&isLocalOllamaProviderHost(r)||l))return cacheProviderHealth(buildHealthResult(e,"needs-setup",`${o} no tiene credenciales configuradas.`,{baseUrl:r}));try{if("minimax"===e)return cacheProviderHealth(buildHealthResult(e,"healthy",`${o} configurado para Anthropic-compatible (${r}).`,{baseUrl:r}));if("ollama"===e||"ollama-cloud"===e){const a=[`${r.endsWith("/v1")?r.slice(0,-3):r}/api/tags`,`${r}/models`];let i,t="";for(const o of a){const a=await fetchWithTimeout(o,n);if(a.ok)return cacheProviderHealth(buildHealthResult(e,"healthy",`Conectado a ${o}.`,{baseUrl:r,statusCode:a.status}));if(i=a.status,t=`${a.status} ${a.statusText}`.trim(),404!==a.status||!o.endsWith("/api/tags"))break}return cacheProviderHealth(429===i?buildHealthResult(e,"rate-limited",`${o} devolvió rate limit al validar la conexión.`,{baseUrl:r,statusCode:i}):buildHealthResult(e,"unreachable",t?`${o} no respondió correctamente (${t}).`:`${o} no respondió correctamente.`,{baseUrl:r,statusCode:i}))}const a=`${r}/models`,i=await fetchWithTimeout(a,n);return i.ok?cacheProviderHealth(buildHealthResult(e,"healthy",`Conectado a ${a}.`,{baseUrl:r,statusCode:i.status})):401===i.status||403===i.status?cacheProviderHealth(buildHealthResult(e,"needs-setup",`${o} rechazó la solicitud. Revisa la API key o token configurado.`,{baseUrl:r,statusCode:i.status})):429===i.status?cacheProviderHealth(buildHealthResult(e,"rate-limited",`${o} devolvió rate limit al validar la conexión.`,{baseUrl:r,statusCode:i.status})):cacheProviderHealth(buildHealthResult(e,"unreachable",`${o} respondió con ${i.status} al validar la conexión.`,{baseUrl:r,statusCode:i.status}))}catch(a){const i=function(e){return e instanceof Error?e.message.replace(/\s+/g," ").trim():String(e).replace(/\s+/g," ").trim()}(a);return"ollama"===e&&(i.toLowerCase().includes("econnrefused")||i.toLowerCase().includes("fetch failed")||i.toLowerCase().includes("networkerror")||i.toLowerCase().includes("localhost:11434"))?cacheProviderHealth(buildHealthResult(e,"unreachable","Ollama no es accesible. Inicia el servidor local o revisa OLLAMA_BASE_URL.",{baseUrl:r})):i.includes("401")||i.includes("403")||i.toLowerCase().includes("authentication")?cacheProviderHealth(buildHealthResult(e,"needs-setup",`${o} no tiene credenciales válidas.`,{baseUrl:r})):i.includes("429")||i.toLowerCase().includes("rate limit")?cacheProviderHealth(buildHealthResult(e,"rate-limited",`${o} devolvió rate limit al validar la conexión.`,{baseUrl:r})):cacheProviderHealth(buildHealthResult(e,"unreachable",`${o} no pudo validarse: ${i||"error desconocido"}.`,{baseUrl:r}))}}export function getCachedProviderModels(e){return d.get(getProviderCacheKey(e))??null}export async function fetchProviderModels(e){const a=getProviderCacheKey(e),i=d.get(a);if(i)return i;try{if("minimax"===e)return d.set(a,l),l;if("deepseek"===e)return d.set(a,s),s;let i=[];if("ollama"===e||"ollama-cloud"===e){const a=getProviderBaseUrl(e),t=a.endsWith("/v1")?a.slice(0,-3):a;try{i=filterOllamaModels(e,function(e){return(e.models??[]).map(e=>{const a=e.model?.trim()||e.name?.trim();if(!a)return null;const i=[e.details?.family,e.details?.parameter_size,e.details?.quantization_level].filter(Boolean);return{value:a,label:e.name?.trim()||a,description:i.join(" · ")}}).filter(e=>null!==e)}(await fetchJson(`${t}/api/tags`,await buildProviderHeaders(e))),a)}catch{i=filterOllamaModels(e,mapOpenAICompatibleModels(await fetchJson(`${a}/models`,await buildProviderHeaders(e)),e),a)}}else{i=mapOpenAICompatibleModels(await fetchJson(`${getProviderBaseUrl(e)}/models`,await buildProviderHeaders(e)),e)}if("gemini-api"===e||"gemini-google"===e){const e=new Set(c.map(e=>e.value));i=[...c,...i.filter(a=>!e.has(a.value))]}return d.set(a,i),i}catch{return"gemini-api"===e||"gemini-google"===e?(d.set(a,c),c):[]}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{MACRO as e,feature as t}from"../../recovery/bunBundleShim.js";import{randomBytes as o}from"crypto";import r from"ignore";import s from"lodash-es/memoize.js";import{homedir as n,tmpdir as i}from"os";import{join as a,normalize as l,posix as c,sep as u}from"path";import{hasAutoMemPathOverride as p,isAutoMemPath as d}from"../../memdir/paths.js";import{isAgentMemoryPath as h}from"../../tools/AgentTool/agentMemory.js";import{CLAUDE_FOLDER_PERMISSION_PATTERN as f,FILE_EDIT_TOOL_NAME as m,GLOBAL_CLAUDE_FOLDER_PERMISSION_PATTERN as g}from"../../tools/FileEditTool/constants.js";import{getOriginalCwd as w,getSessionId as P}from"../../bootstrap/state.js";import{checkStatsigFeatureGate_CACHED_MAY_BE_STALE as v}from"../../services/analytics/growthbook.js";import{FILE_READ_TOOL_NAME as y}from"../../tools/FileReadTool/prompt.js";import{getCwd as C}from"../cwd.js";import{getClaudeConfigHomeDir as R}from"../envUtils.js";import{getFsImplementation as b,getPathsForPermissionCheck as k}from"../fsOperations.js";import{containsPathTraversal as S,expandPath as W,getDirectoryForPath as I,sanitizePath as x}from"../path.js";import{getPlanSlug as D,getPlansDirectory as F}from"../plans.js";import{getPlatform as j}from"../platform.js";import{getProjectDir as $}from"../sessionStorage.js";import{SETTING_SOURCES as E}from"../settings/constants.js";import{getSettingsFilePathForSource as T,getSettingsRootPathForSource as A}from"../settings/settings.js";import{containsVulnerableUncPath as z}from"../shell/readOnlyCommandValidation.js";import{getToolResultsDir as O}from"../toolResultStorage.js";import{windowsPathToPosixPath as N}from"../windowsPaths.js";import{createReadRuleSuggestion as M}from"./PermissionUpdate.js";import{getRuleByContentsForToolName as _}from"./permissions.js";export const DANGEROUS_FILES=[".gitconfig",".gitmodules",".bashrc",".bash_profile",".zshrc",".zprofile",".profile",".ripgreprc",".mcp.json",".claude.json"];export const DANGEROUS_DIRECTORIES=[".git",".vscode",".idea",".claude"];export function normalizeCaseForComparison(e){return e.toLowerCase()}export function getClaudeSkillScope(e){const t=W(e),o=normalizeCaseForComparison(t),r=[{dir:W(a(w(),".context","skills")),prefix:"/.context/skills/"},{dir:W(a(R(),"skills")),prefix:"~/.context/skills/"},{dir:W(a(w(),".context","skills")),prefix:"/.context/skills/"},{dir:W(a(n(),".context","skills")),prefix:"~/.context/skills/"}];for(const{dir:e,prefix:s}of r){const r=normalizeCaseForComparison(e);for(const n of[u,"/"])if(o.startsWith(r+n.toLowerCase())){const o=t.slice(e.length+n.length),r=o.indexOf("/"),i="\\"===u?o.indexOf("\\"):-1,a=-1===r?i:-1===i?r:Math.min(r,i);if(a<=0)return null;const l=o.slice(0,a);return!l||"."===l||l.includes("..")||/[*?[\]]/.test(l)?null:{skillName:l,pattern:s+l+"/**"}}}return null}const U=c.sep;export function relativePath(e,t){if("windows"===j()){const o=N(e),r=N(t);return c.relative(o,r)}return c.relative(e,t)}export function toPosixPath(e){return"windows"===j()?N(e):e}export function isClaudeSettingsPath(e){const t=normalizeCaseForComparison(W(e));return!(!t.endsWith(`${u}.context${u}settings.json`)&&!t.endsWith(`${u}.context${u}settings.local.json`))||E.map(e=>T(e)).filter(e=>void 0!==e).some(e=>normalizeCaseForComparison(e)===t)}function isClaudeConfigFilePath(e){if(isClaudeSettingsPath(e))return!0;const t=a(w(),".claude","commands"),o=a(w(),".claude","agents"),r=a(w(),".claude","skills"),s=a(w(),".context","commands"),n=a(w(),".context","agents"),i=a(w(),".context","skills");return pathInWorkingPath(e,t)||pathInWorkingPath(e,o)||pathInWorkingPath(e,r)||pathInWorkingPath(e,s)||pathInWorkingPath(e,n)||pathInWorkingPath(e,i)}function isSessionPlanFile(e){const t=a(F(),D()),o=l(e);return o.startsWith(t)&&o.endsWith(".md")}export function getSessionMemoryDir(){return a($(C()),P(),"session-memory")+u}export function getSessionMemoryPath(){return a(getSessionMemoryDir(),"summary.md")}export function isScratchpadEnabled(){return v("tengu_scratch")}export function getClaudeTempDirName(){if("windows"===j())return"claude";return`claude-${process.getuid?.()??0}`}export const getClaudeTempDir=s(function(){const e=process.env.CONTEXT_CODE_TMPDIR||process.env.CLAUDE_CODE_TMPDIR||("windows"===j()?i():"/tmp"),t=b();let o=e;try{o=t.realpathSync(e)}catch{}return a(o,getClaudeTempDirName())+u});export const getBundledSkillsRoot=s(function(){const t=o(16).toString("hex");return a(getClaudeTempDir(),"bundled-skills",e.VERSION,t)});export function getProjectTempDir(){return a(getClaudeTempDir(),x(w()))+u}export function getScratchpadDir(){return a(getProjectTempDir(),P(),"scratchpad")}export async function ensureScratchpadDir(){if(!isScratchpadEnabled())throw new Error("Scratchpad directory feature is not enabled");const e=b(),t=getScratchpadDir();return await e.mkdir(t,{mode:448}),t}function isScratchpadPath(e){if(!isScratchpadEnabled())return!1;const t=getScratchpadDir(),o=l(e);return o===t||o.startsWith(t+u)}function isDangerousFilePathToAutoEdit(e){const t=W(e).split(u),o=t.at(-1);if(e.startsWith("\\\\")||e.startsWith("//"))return!0;for(let e=0;e<t.length;e++){const o=normalizeCaseForComparison(t[e]);for(const r of DANGEROUS_DIRECTORIES)if(o===normalizeCaseForComparison(r)){if(".claude"===r){const o=t[e+1];if(o&&"worktrees"===normalizeCaseForComparison(o))break}return!0}}if(o){const e=normalizeCaseForComparison(o);if(DANGEROUS_FILES.some(t=>normalizeCaseForComparison(t)===e))return!0}return!1}function hasSuspiciousWindowsPathPattern(e){if("windows"===j()||"wsl"===j()){if(-1!==e.indexOf(":",2))return!0}return!!/~\d/.test(e)||(!!(e.startsWith("\\\\?\\")||e.startsWith("\\\\.\\")||e.startsWith("//?/")||e.startsWith("//./"))||(!!/[.\s]+$/.test(e)||(!!/\.(CON|PRN|AUX|NUL|COM[1-9]|LPT[1-9])$/i.test(e)||(!!/(^|\/|\\)\.{3,}(\/|\\|$)/.test(e)||!!z(e)))))}export function checkPathSafetyForAutoEdit(e,t){const o=t??k(e);for(const t of o)if(hasSuspiciousWindowsPathPattern(t))return{safe:!1,message:`Claude requested permissions to write to ${e}, which contains a suspicious Windows path pattern that requires manual approval.`,classifierApprovable:!1};for(const t of o)if(isClaudeConfigFilePath(t))return{safe:!1,message:`Context solicitó permisos para escribir en ${e}, pero aún no se los has otorgado.`,classifierApprovable:!0};for(const t of o)if(isDangerousFilePathToAutoEdit(t))return{safe:!1,message:`Claude requested permissions to edit ${e} which is a sensitive file.`,classifierApprovable:!0};return{safe:!0}}export function allWorkingDirectories(e){return new Set([w(),...e.additionalWorkingDirectories.keys()])}export const getResolvedWorkingDirPaths=s(k);export function pathInAllowedWorkingPath(e,t,o){const r=o??k(e),s=Array.from(allWorkingDirectories(t)).flatMap(e=>getResolvedWorkingDirPaths(e));return r.every(e=>s.some(t=>pathInWorkingPath(e,t)))}export function pathInWorkingPath(e,t){const o=W(e),r=W(t),s=o.replace(/^\/private\/var\//,"/var/").replace(/^\/private\/tmp(\/|$)/,"/tmp$1"),n=r.replace(/^\/private\/var\//,"/var/").replace(/^\/private\/tmp(\/|$)/,"/tmp$1"),i=normalizeCaseForComparison(s),a=relativePath(normalizeCaseForComparison(n),i);return""===a||!S(a)&&!c.isAbsolute(a)}function rootPathForSource(e){switch(e){case"cliArg":case"command":case"session":return W(w());case"userSettings":case"policySettings":case"projectSettings":case"localSettings":case"flagSettings":return A(e)}}function prependDirSep(e){return c.join(U,e)}function normalizePatternToPath({patternRoot:e,pattern:t,rootPath:o}){const r=c.join(e,t);if(e===o)return prependDirSep(t);if(r.startsWith(`${o}${U}`)){return prependDirSep(r.slice(o.length))}{const r=c.relative(o,e);if(!r||r.startsWith(`..${U}`)||".."===r)return null;return prependDirSep(c.join(r,t))}}export function normalizePatternsToPath(e,t){const o=new Set(e.get(null)??[]);for(const[r,s]of e.entries())if(null!==r)for(const e of s){const s=normalizePatternToPath({patternRoot:r,pattern:e,rootPath:t});s&&o.add(s)}return Array.from(o)}export function getFileReadIgnorePatterns(e){const t=getPatternsByRoot(e,"read","deny"),o=new Map;for(const[e,r]of t.entries())o.set(e,Array.from(r.keys()));return o}function patternWithRoot(e,t){if(e.startsWith(`${U}${U}`)){const t=e.slice(1);if("windows"===j()&&t.match(/^\/[a-z]\//i)){const e=t[1]?.toUpperCase()??"C",o=t.slice(2),r=`${e}:\\`;return{relativePattern:o.startsWith("/")?o.slice(1):o,root:r}}return{relativePattern:t,root:U}}if(e.startsWith(`~${U}`))return{relativePattern:e.slice(1),root:n().normalize("NFC")};if(e.startsWith(U))return{relativePattern:e,root:rootPathForSource(t)};let o=e;return e.startsWith(`.${U}`)&&(o=e.slice(2)),{relativePattern:o,root:null}}function getPatternsByRoot(e,t,o){const r=(()=>{switch(t){case"edit":return m;case"read":return y}})(),s=_(e,r,o),n=new Map;for(const[e,t]of s.entries()){const{relativePattern:o,root:r}=patternWithRoot(e,t.source);let s=n.get(r);void 0===s&&(s=new Map,n.set(r,s)),s.set(o,t)}return n}export function matchingRuleForInput(e,t,o,s){let n=W(e);"windows"===j()&&n.includes("\\")&&(n=N(n));const i=getPatternsByRoot(t,o,s);for(const[e,t]of i.entries()){const o=Array.from(t.keys()).map(e=>{let t=e;return t.endsWith("/**")&&(t=t.slice(0,-3)),t}),s=r().add(o),i=relativePath(e??C(),n??C());if(i.startsWith(`..${U}`))continue;if(!i)continue;const a=s.test(i);if(a.ignored&&a.rule){const e=a.rule.pattern,o=e+"/**";return t.has(o)?t.get(o)??null:t.get(e)??null}}return null}export function checkReadPermissionForTool(e,t,o){if("function"!=typeof e.getPath)return{behavior:"ask",message:`Claude requested permissions to use ${e.name}, but you haven't granted it yet.`};const r=e.getPath(t),s=k(r);for(const e of s)if(e.startsWith("\\\\")||e.startsWith("//"))return{behavior:"ask",message:`Claude requested permissions to read from ${r}, which appears to be a UNC path that could access network resources.`,decisionReason:{type:"other",reason:"UNC path detected (defense-in-depth check)"}};for(const e of s)if(hasSuspiciousWindowsPathPattern(e))return{behavior:"ask",message:`Claude requested permissions to read from ${r}, which contains a suspicious Windows path pattern that requires manual approval.`,decisionReason:{type:"other",reason:"Path contains suspicious Windows-specific patterns (alternate data streams, short names, long path prefixes, or three or more consecutive dots) that require manual verification"}};for(const e of s){const t=matchingRuleForInput(e,o,"read","deny");if(t)return{behavior:"deny",message:`Permission to read ${r} has been denied.`,decisionReason:{type:"rule",rule:t}}}for(const e of s){const t=matchingRuleForInput(e,o,"read","ask");if(t)return{behavior:"ask",message:`Context solicitó permisos para leer desde ${r}, pero aún no se los has otorgado.`,decisionReason:{type:"rule",rule:t}}}const n=checkWritePermissionForTool(e,t,o,s);if("allow"===n.behavior)return n;if(pathInAllowedWorkingPath(r,o,s))return{behavior:"allow",updatedInput:t,decisionReason:{type:"mode",mode:"default"}};const i=checkReadableInternalPath(W(r),t);if("passthrough"!==i.behavior)return i;const a=matchingRuleForInput(r,o,"read","allow");return a?{behavior:"allow",updatedInput:t,decisionReason:{type:"rule",rule:a}}:{behavior:"ask",message:`Context solicitó permisos para leer desde ${r}, pero aún no se los has otorgado.`,suggestions:generateSuggestions(r,"read",o,s),decisionReason:{type:"workingDir",reason:"Path is outside allowed working directories"}}}export function checkWritePermissionForTool(e,t,o,r){if("function"!=typeof e.getPath)return{behavior:"ask",message:`Claude requested permissions to use ${e.name}, but you haven't granted it yet.`};const s=e.getPath(t),n=r??k(s);for(const e of n){const t=matchingRuleForInput(e,o,"edit","deny");if(t)return{behavior:"deny",message:`Permission to edit ${s} has been denied.`,decisionReason:{type:"rule",rule:t}}}const i=checkEditableInternalPath(W(s),t);if("passthrough"!==i.behavior)return i;const a=matchingRuleForInput(s,{...o,alwaysAllowRules:{session:o.alwaysAllowRules.session??[]}},"edit","allow");if(a){const e=a.ruleValue.ruleContent;if(e&&(e.startsWith(f.slice(0,-2))||e.startsWith(g.slice(0,-2)))&&!e.includes("..")&&e.endsWith("/**"))return{behavior:"allow",updatedInput:t,decisionReason:{type:"rule",rule:a}}}const l=checkPathSafetyForAutoEdit(s,n);if(!l.safe){const e=getClaudeSkillScope(s),t=e?[{type:"addRules",rules:[{toolName:m,ruleContent:e.pattern}],behavior:"allow",destination:"session"}]:generateSuggestions(s,"write",o,n);return{behavior:"ask",message:l.message,suggestions:t,decisionReason:{type:"safetyCheck",reason:l.message,classifierApprovable:l.classifierApprovable}}}for(const e of n){const t=matchingRuleForInput(e,o,"edit","ask");if(t)return{behavior:"ask",message:`Context solicitó permisos para escribir en ${s}, pero aún no se los has otorgado.`,decisionReason:{type:"rule",rule:t}}}const c=pathInAllowedWorkingPath(s,o,n);if("acceptEdits"===o.mode&&c)return{behavior:"allow",updatedInput:t,decisionReason:{type:"mode",mode:o.mode}};const u=matchingRuleForInput(s,o,"edit","allow");return u?{behavior:"allow",updatedInput:t,decisionReason:{type:"rule",rule:u}}:{behavior:"ask",message:`Context solicitó permisos para escribir en ${s}, pero aún no se los has otorgado.`,suggestions:generateSuggestions(s,"write",o,n),decisionReason:c?void 0:{type:"workingDir",reason:"Path is outside allowed working directories"}}}export function generateSuggestions(e,t,o,r){const s=!pathInAllowedWorkingPath(e,o,r);if("read"===t&&s){const t=I(e);return k(t).map(e=>M(e,"session")).filter(e=>void 0!==e)}const n="default"===o.mode||"plan"===o.mode;if("write"===t||"create"===t){const t=n?[{type:"setMode",mode:"acceptEdits",destination:"session"}]:[];if(s){const o=I(e),r=k(o);t.push({type:"addDirectories",directories:r,destination:"session"})}return t}return n?[{type:"setMode",mode:"acceptEdits",destination:"session"}]:[]}export function checkEditableInternalPath(e,o){const r=l(e);if(isSessionPlanFile(r))return{behavior:"allow",updatedInput:o,decisionReason:{type:"other",reason:"Plan files for current session are allowed for writing"}};if(isScratchpadPath(r))return{behavior:"allow",updatedInput:o,decisionReason:{type:"other",reason:"Scratchpad files for current session are allowed for writing"}};if(t("TEMPLATES")){const t=process.env.CONTEXT_JOB_DIR??process.env.CLAUDE_JOB_DIR;if(t){const r=a(R(),"jobs"),s=k(t).map(l),n=k(r).map(l);if(s.every(e=>n.some(t=>e.startsWith(t+u)))){if(k(e).every(e=>{const t=l(e);return s.some(e=>t===e||t.startsWith(e+u))}))return{behavior:"allow",updatedInput:o,decisionReason:{type:"other",reason:"Job directory files for current job are allowed for writing"}}}}}return h(r)?{behavior:"allow",updatedInput:o,decisionReason:{type:"other",reason:"Agent memory files are allowed for writing"}}:!p()&&d(r)?{behavior:"allow",updatedInput:o,decisionReason:{type:"other",reason:"auto memory files are allowed for writing"}}:normalizeCaseForComparison(r)===normalizeCaseForComparison(a(w(),".claude","launch.json"))?{behavior:"allow",updatedInput:o,decisionReason:{type:"other",reason:"Preview launch config is allowed for writing"}}:{behavior:"passthrough",message:""}}export function checkReadableInternalPath(e,t){const o=l(e);if(function(e){return l(e).startsWith(getSessionMemoryDir())}(o))return{behavior:"allow",updatedInput:t,decisionReason:{type:"other",reason:"Session memory files are allowed for reading"}};if(function(e){const t=$(C()),o=l(e);return o===t||o.startsWith(t+u)}(o))return{behavior:"allow",updatedInput:t,decisionReason:{type:"other",reason:"Project directory files are allowed for reading"}};if(isSessionPlanFile(o))return{behavior:"allow",updatedInput:t,decisionReason:{type:"other",reason:"Plan files for current session are allowed for reading"}};const r=O(),s=r.endsWith(u)?r:r+u;if(o===r||o.startsWith(s))return{behavior:"allow",updatedInput:t,decisionReason:{type:"other",reason:"Tool result files are allowed for reading"}};if(isScratchpadPath(o))return{behavior:"allow",updatedInput:t,decisionReason:{type:"other",reason:"Scratchpad files for current session are allowed for reading"}};const n=getProjectTempDir();if(o.startsWith(n))return{behavior:"allow",updatedInput:t,decisionReason:{type:"other",reason:"Project temp directory files are allowed for reading"}};if(h(o))return{behavior:"allow",updatedInput:t,decisionReason:{type:"other",reason:"Agent memory files are allowed for reading"}};if(d(o))return{behavior:"allow",updatedInput:t,decisionReason:{type:"other",reason:"auto memory files are allowed for reading"}};const i=a(R(),"tasks")+u;if(o===i.slice(0,-1)||o.startsWith(i))return{behavior:"allow",updatedInput:t,decisionReason:{type:"other",reason:"Task files are allowed for reading"}};const c=a(R(),"teams")+u;if(o===c.slice(0,-1)||o.startsWith(c))return{behavior:"allow",updatedInput:t,decisionReason:{type:"other",reason:"Team files are allowed for reading"}};const p=getBundledSkillsRoot()+u;return o.startsWith(p)?{behavior:"allow",updatedInput:t,decisionReason:{type:"other",reason:"Bundled skill reference files are allowed for reading"}}:{behavior:"passthrough",message:""}}
|
|
1
|
+
import{MACRO as e,feature as t}from"../../recovery/bunBundleShim.js";import{randomBytes as o}from"crypto";import r from"ignore";import s from"lodash-es/memoize.js";import{homedir as n,tmpdir as i}from"os";import{join as a,normalize as l,posix as c,sep as u}from"path";import{hasAutoMemPathOverride as p,isAutoMemPath as d}from"../../memdir/paths.js";import{isAgentMemoryPath as h}from"../../tools/AgentTool/agentMemory.js";import{CLAUDE_FOLDER_PERMISSION_PATTERN as f,FILE_EDIT_TOOL_NAME as m,GLOBAL_CLAUDE_FOLDER_PERMISSION_PATTERN as g}from"../../tools/FileEditTool/constants.js";import{getOriginalCwd as w,getSessionId as P}from"../../bootstrap/state.js";import{checkStatsigFeatureGate_CACHED_MAY_BE_STALE as v}from"../../services/analytics/growthbook.js";import{FILE_READ_TOOL_NAME as y}from"../../tools/FileReadTool/prompt.js";import{getCwd as C}from"../cwd.js";import{getClaudeConfigHomeDir as R}from"../envUtils.js";import{getFsImplementation as b,getPathsForPermissionCheck as k}from"../fsOperations.js";import{containsPathTraversal as S,expandPath as W,getDirectoryForPath as x,sanitizePath as I}from"../path.js";import{getPlanSlug as D,getPlansDirectory as F}from"../plans.js";import{getPlatform as j}from"../platform.js";import{getProjectDir as $}from"../sessionStorage.js";import{SETTING_SOURCES as E}from"../settings/constants.js";import{getSettingsFilePathForSource as T,getSettingsRootPathForSource as A}from"../settings/settings.js";import{containsVulnerableUncPath as z}from"../shell/readOnlyCommandValidation.js";import{getToolResultsDir as O}from"../toolResultStorage.js";import{windowsPathToPosixPath as N}from"../windowsPaths.js";import{createReadRuleSuggestion as M}from"./PermissionUpdate.js";import{getRuleByContentsForToolName as _}from"./permissions.js";export const DANGEROUS_FILES=[".gitconfig",".gitmodules",".bashrc",".bash_profile",".zshrc",".zprofile",".profile",".ripgreprc",".mcp.json",".claude.json",".context.json"];export const DANGEROUS_DIRECTORIES=[".git",".vscode",".idea",".claude"];export function normalizeCaseForComparison(e){return e.toLowerCase()}export function getClaudeSkillScope(e){const t=W(e),o=normalizeCaseForComparison(t),r=[{dir:W(a(w(),".context","skills")),prefix:"/.context/skills/"},{dir:W(a(R(),"skills")),prefix:"~/.context/skills/"},{dir:W(a(w(),".context","skills")),prefix:"/.context/skills/"},{dir:W(a(n(),".context","skills")),prefix:"~/.context/skills/"}];for(const{dir:e,prefix:s}of r){const r=normalizeCaseForComparison(e);for(const n of[u,"/"])if(o.startsWith(r+n.toLowerCase())){const o=t.slice(e.length+n.length),r=o.indexOf("/"),i="\\"===u?o.indexOf("\\"):-1,a=-1===r?i:-1===i?r:Math.min(r,i);if(a<=0)return null;const l=o.slice(0,a);return!l||"."===l||l.includes("..")||/[*?[\]]/.test(l)?null:{skillName:l,pattern:s+l+"/**"}}}return null}const U=c.sep;export function relativePath(e,t){if("windows"===j()){const o=N(e),r=N(t);return c.relative(o,r)}return c.relative(e,t)}export function toPosixPath(e){return"windows"===j()?N(e):e}export function isClaudeSettingsPath(e){const t=normalizeCaseForComparison(W(e));return!(!t.endsWith(`${u}.context${u}settings.json`)&&!t.endsWith(`${u}.context${u}settings.local.json`))||E.map(e=>T(e)).filter(e=>void 0!==e).some(e=>normalizeCaseForComparison(e)===t)}function isClaudeConfigFilePath(e){if(isClaudeSettingsPath(e))return!0;const t=a(w(),".claude","commands"),o=a(w(),".claude","agents"),r=a(w(),".claude","skills"),s=a(w(),".context","commands"),n=a(w(),".context","agents"),i=a(w(),".context","skills");return pathInWorkingPath(e,t)||pathInWorkingPath(e,o)||pathInWorkingPath(e,r)||pathInWorkingPath(e,s)||pathInWorkingPath(e,n)||pathInWorkingPath(e,i)}function isSessionPlanFile(e){const t=a(F(),D()),o=l(e);return o.startsWith(t)&&o.endsWith(".md")}export function getSessionMemoryDir(){return a($(C()),P(),"session-memory")+u}export function getSessionMemoryPath(){return a(getSessionMemoryDir(),"summary.md")}export function isScratchpadEnabled(){return v("tengu_scratch")}export function getClaudeTempDirName(){if("windows"===j())return"claude";return`claude-${process.getuid?.()??0}`}export const getClaudeTempDir=s(function(){const e=process.env.CONTEXT_CODE_TMPDIR||process.env.CLAUDE_CODE_TMPDIR||("windows"===j()?i():"/tmp"),t=b();let o=e;try{o=t.realpathSync(e)}catch{}return a(o,getClaudeTempDirName())+u});export const getBundledSkillsRoot=s(function(){const t=o(16).toString("hex");return a(getClaudeTempDir(),"bundled-skills",e.VERSION,t)});export function getProjectTempDir(){return a(getClaudeTempDir(),I(w()))+u}export function getScratchpadDir(){return a(getProjectTempDir(),P(),"scratchpad")}export async function ensureScratchpadDir(){if(!isScratchpadEnabled())throw new Error("Scratchpad directory feature is not enabled");const e=b(),t=getScratchpadDir();return await e.mkdir(t,{mode:448}),t}function isScratchpadPath(e){if(!isScratchpadEnabled())return!1;const t=getScratchpadDir(),o=l(e);return o===t||o.startsWith(t+u)}function isDangerousFilePathToAutoEdit(e){const t=W(e).split(u),o=t.at(-1);if(e.startsWith("\\\\")||e.startsWith("//"))return!0;for(let e=0;e<t.length;e++){const o=normalizeCaseForComparison(t[e]);for(const r of DANGEROUS_DIRECTORIES)if(o===normalizeCaseForComparison(r)){if(".claude"===r){const o=t[e+1];if(o&&"worktrees"===normalizeCaseForComparison(o))break}return!0}}if(o){const e=normalizeCaseForComparison(o);if(DANGEROUS_FILES.some(t=>normalizeCaseForComparison(t)===e))return!0}return!1}function hasSuspiciousWindowsPathPattern(e){if("windows"===j()||"wsl"===j()){if(-1!==e.indexOf(":",2))return!0}return!!/~\d/.test(e)||(!!(e.startsWith("\\\\?\\")||e.startsWith("\\\\.\\")||e.startsWith("//?/")||e.startsWith("//./"))||(!!/[.\s]+$/.test(e)||(!!/\.(CON|PRN|AUX|NUL|COM[1-9]|LPT[1-9])$/i.test(e)||(!!/(^|\/|\\)\.{3,}(\/|\\|$)/.test(e)||!!z(e)))))}export function checkPathSafetyForAutoEdit(e,t){const o=t??k(e);for(const t of o)if(hasSuspiciousWindowsPathPattern(t))return{safe:!1,message:`Claude requested permissions to write to ${e}, which contains a suspicious Windows path pattern that requires manual approval.`,classifierApprovable:!1};for(const t of o)if(isClaudeConfigFilePath(t))return{safe:!1,message:`Context solicitó permisos para escribir en ${e}, pero aún no se los has otorgado.`,classifierApprovable:!0};for(const t of o)if(isDangerousFilePathToAutoEdit(t))return{safe:!1,message:`Claude requested permissions to edit ${e} which is a sensitive file.`,classifierApprovable:!0};return{safe:!0}}export function allWorkingDirectories(e){return new Set([w(),...e.additionalWorkingDirectories.keys()])}export const getResolvedWorkingDirPaths=s(k);export function pathInAllowedWorkingPath(e,t,o){const r=o??k(e),s=Array.from(allWorkingDirectories(t)).flatMap(e=>getResolvedWorkingDirPaths(e));return r.every(e=>s.some(t=>pathInWorkingPath(e,t)))}export function pathInWorkingPath(e,t){const o=W(e),r=W(t),s=o.replace(/^\/private\/var\//,"/var/").replace(/^\/private\/tmp(\/|$)/,"/tmp$1"),n=r.replace(/^\/private\/var\//,"/var/").replace(/^\/private\/tmp(\/|$)/,"/tmp$1"),i=normalizeCaseForComparison(s),a=relativePath(normalizeCaseForComparison(n),i);return""===a||!S(a)&&!c.isAbsolute(a)}function rootPathForSource(e){switch(e){case"cliArg":case"command":case"session":return W(w());case"userSettings":case"policySettings":case"projectSettings":case"localSettings":case"flagSettings":return A(e)}}function prependDirSep(e){return c.join(U,e)}function normalizePatternToPath({patternRoot:e,pattern:t,rootPath:o}){const r=c.join(e,t);if(e===o)return prependDirSep(t);if(r.startsWith(`${o}${U}`)){return prependDirSep(r.slice(o.length))}{const r=c.relative(o,e);if(!r||r.startsWith(`..${U}`)||".."===r)return null;return prependDirSep(c.join(r,t))}}export function normalizePatternsToPath(e,t){const o=new Set(e.get(null)??[]);for(const[r,s]of e.entries())if(null!==r)for(const e of s){const s=normalizePatternToPath({patternRoot:r,pattern:e,rootPath:t});s&&o.add(s)}return Array.from(o)}export function getFileReadIgnorePatterns(e){const t=getPatternsByRoot(e,"read","deny"),o=new Map;for(const[e,r]of t.entries())o.set(e,Array.from(r.keys()));return o}function patternWithRoot(e,t){if(e.startsWith(`${U}${U}`)){const t=e.slice(1);if("windows"===j()&&t.match(/^\/[a-z]\//i)){const e=t[1]?.toUpperCase()??"C",o=t.slice(2),r=`${e}:\\`;return{relativePattern:o.startsWith("/")?o.slice(1):o,root:r}}return{relativePattern:t,root:U}}if(e.startsWith(`~${U}`))return{relativePattern:e.slice(1),root:n().normalize("NFC")};if(e.startsWith(U))return{relativePattern:e,root:rootPathForSource(t)};let o=e;return e.startsWith(`.${U}`)&&(o=e.slice(2)),{relativePattern:o,root:null}}function getPatternsByRoot(e,t,o){const r=(()=>{switch(t){case"edit":return m;case"read":return y}})(),s=_(e,r,o),n=new Map;for(const[e,t]of s.entries()){const{relativePattern:o,root:r}=patternWithRoot(e,t.source);let s=n.get(r);void 0===s&&(s=new Map,n.set(r,s)),s.set(o,t)}return n}export function matchingRuleForInput(e,t,o,s){let n=W(e);"windows"===j()&&n.includes("\\")&&(n=N(n));const i=getPatternsByRoot(t,o,s);for(const[e,t]of i.entries()){const o=Array.from(t.keys()).map(e=>{let t=e;return t.endsWith("/**")&&(t=t.slice(0,-3)),t}),s=r().add(o),i=relativePath(e??C(),n??C());if(i.startsWith(`..${U}`))continue;if(!i)continue;const a=s.test(i);if(a.ignored&&a.rule){const e=a.rule.pattern,o=e+"/**";return t.has(o)?t.get(o)??null:t.get(e)??null}}return null}export function checkReadPermissionForTool(e,t,o){if("function"!=typeof e.getPath)return{behavior:"ask",message:`Claude requested permissions to use ${e.name}, but you haven't granted it yet.`};const r=e.getPath(t),s=k(r);for(const e of s)if(e.startsWith("\\\\")||e.startsWith("//"))return{behavior:"ask",message:`Claude requested permissions to read from ${r}, which appears to be a UNC path that could access network resources.`,decisionReason:{type:"other",reason:"UNC path detected (defense-in-depth check)"}};for(const e of s)if(hasSuspiciousWindowsPathPattern(e))return{behavior:"ask",message:`Claude requested permissions to read from ${r}, which contains a suspicious Windows path pattern that requires manual approval.`,decisionReason:{type:"other",reason:"Path contains suspicious Windows-specific patterns (alternate data streams, short names, long path prefixes, or three or more consecutive dots) that require manual verification"}};for(const e of s){const t=matchingRuleForInput(e,o,"read","deny");if(t)return{behavior:"deny",message:`Permission to read ${r} has been denied.`,decisionReason:{type:"rule",rule:t}}}for(const e of s){const t=matchingRuleForInput(e,o,"read","ask");if(t)return{behavior:"ask",message:`Context solicitó permisos para leer desde ${r}, pero aún no se los has otorgado.`,decisionReason:{type:"rule",rule:t}}}const n=checkWritePermissionForTool(e,t,o,s);if("allow"===n.behavior)return n;if(pathInAllowedWorkingPath(r,o,s))return{behavior:"allow",updatedInput:t,decisionReason:{type:"mode",mode:"default"}};const i=checkReadableInternalPath(W(r),t);if("passthrough"!==i.behavior)return i;const a=matchingRuleForInput(r,o,"read","allow");return a?{behavior:"allow",updatedInput:t,decisionReason:{type:"rule",rule:a}}:{behavior:"ask",message:`Context solicitó permisos para leer desde ${r}, pero aún no se los has otorgado.`,suggestions:generateSuggestions(r,"read",o,s),decisionReason:{type:"workingDir",reason:"Path is outside allowed working directories"}}}export function checkWritePermissionForTool(e,t,o,r){if("function"!=typeof e.getPath)return{behavior:"ask",message:`Claude requested permissions to use ${e.name}, but you haven't granted it yet.`};const s=e.getPath(t),n=r??k(s);for(const e of n){const t=matchingRuleForInput(e,o,"edit","deny");if(t)return{behavior:"deny",message:`Permission to edit ${s} has been denied.`,decisionReason:{type:"rule",rule:t}}}const i=checkEditableInternalPath(W(s),t);if("passthrough"!==i.behavior)return i;const a=matchingRuleForInput(s,{...o,alwaysAllowRules:{session:o.alwaysAllowRules.session??[]}},"edit","allow");if(a){const e=a.ruleValue.ruleContent;if(e&&(e.startsWith(f.slice(0,-2))||e.startsWith(g.slice(0,-2)))&&!e.includes("..")&&e.endsWith("/**"))return{behavior:"allow",updatedInput:t,decisionReason:{type:"rule",rule:a}}}const l=checkPathSafetyForAutoEdit(s,n);if(!l.safe){const e=getClaudeSkillScope(s),t=e?[{type:"addRules",rules:[{toolName:m,ruleContent:e.pattern}],behavior:"allow",destination:"session"}]:generateSuggestions(s,"write",o,n);return{behavior:"ask",message:l.message,suggestions:t,decisionReason:{type:"safetyCheck",reason:l.message,classifierApprovable:l.classifierApprovable}}}for(const e of n){const t=matchingRuleForInput(e,o,"edit","ask");if(t)return{behavior:"ask",message:`Context solicitó permisos para escribir en ${s}, pero aún no se los has otorgado.`,decisionReason:{type:"rule",rule:t}}}const c=pathInAllowedWorkingPath(s,o,n);if("acceptEdits"===o.mode&&c)return{behavior:"allow",updatedInput:t,decisionReason:{type:"mode",mode:o.mode}};const u=matchingRuleForInput(s,o,"edit","allow");return u?{behavior:"allow",updatedInput:t,decisionReason:{type:"rule",rule:u}}:{behavior:"ask",message:`Context solicitó permisos para escribir en ${s}, pero aún no se los has otorgado.`,suggestions:generateSuggestions(s,"write",o,n),decisionReason:c?void 0:{type:"workingDir",reason:"Path is outside allowed working directories"}}}export function generateSuggestions(e,t,o,r){const s=!pathInAllowedWorkingPath(e,o,r);if("read"===t&&s){const t=x(e);return k(t).map(e=>M(e,"session")).filter(e=>void 0!==e)}const n="default"===o.mode||"plan"===o.mode;if("write"===t||"create"===t){const t=n?[{type:"setMode",mode:"acceptEdits",destination:"session"}]:[];if(s){const o=x(e),r=k(o);t.push({type:"addDirectories",directories:r,destination:"session"})}return t}return n?[{type:"setMode",mode:"acceptEdits",destination:"session"}]:[]}export function checkEditableInternalPath(e,o){const r=l(e);if(isSessionPlanFile(r))return{behavior:"allow",updatedInput:o,decisionReason:{type:"other",reason:"Plan files for current session are allowed for writing"}};if(isScratchpadPath(r))return{behavior:"allow",updatedInput:o,decisionReason:{type:"other",reason:"Scratchpad files for current session are allowed for writing"}};if(t("TEMPLATES")){const t=process.env.CONTEXT_JOB_DIR??process.env.CLAUDE_JOB_DIR;if(t){const r=a(R(),"jobs"),s=k(t).map(l),n=k(r).map(l);if(s.every(e=>n.some(t=>e.startsWith(t+u)))){if(k(e).every(e=>{const t=l(e);return s.some(e=>t===e||t.startsWith(e+u))}))return{behavior:"allow",updatedInput:o,decisionReason:{type:"other",reason:"Job directory files for current job are allowed for writing"}}}}}return h(r)?{behavior:"allow",updatedInput:o,decisionReason:{type:"other",reason:"Agent memory files are allowed for writing"}}:!p()&&d(r)?{behavior:"allow",updatedInput:o,decisionReason:{type:"other",reason:"auto memory files are allowed for writing"}}:normalizeCaseForComparison(r)===normalizeCaseForComparison(a(w(),".claude","launch.json"))?{behavior:"allow",updatedInput:o,decisionReason:{type:"other",reason:"Preview launch config is allowed for writing"}}:{behavior:"passthrough",message:""}}export function checkReadableInternalPath(e,t){const o=l(e);if(function(e){return l(e).startsWith(getSessionMemoryDir())}(o))return{behavior:"allow",updatedInput:t,decisionReason:{type:"other",reason:"Session memory files are allowed for reading"}};if(function(e){const t=$(C()),o=l(e);return o===t||o.startsWith(t+u)}(o))return{behavior:"allow",updatedInput:t,decisionReason:{type:"other",reason:"Project directory files are allowed for reading"}};if(isSessionPlanFile(o))return{behavior:"allow",updatedInput:t,decisionReason:{type:"other",reason:"Plan files for current session are allowed for reading"}};const r=O(),s=r.endsWith(u)?r:r+u;if(o===r||o.startsWith(s))return{behavior:"allow",updatedInput:t,decisionReason:{type:"other",reason:"Tool result files are allowed for reading"}};if(isScratchpadPath(o))return{behavior:"allow",updatedInput:t,decisionReason:{type:"other",reason:"Scratchpad files for current session are allowed for reading"}};const n=getProjectTempDir();if(o.startsWith(n))return{behavior:"allow",updatedInput:t,decisionReason:{type:"other",reason:"Project temp directory files are allowed for reading"}};if(h(o))return{behavior:"allow",updatedInput:t,decisionReason:{type:"other",reason:"Agent memory files are allowed for reading"}};if(d(o))return{behavior:"allow",updatedInput:t,decisionReason:{type:"other",reason:"auto memory files are allowed for reading"}};const i=a(R(),"tasks")+u;if(o===i.slice(0,-1)||o.startsWith(i))return{behavior:"allow",updatedInput:t,decisionReason:{type:"other",reason:"Task files are allowed for reading"}};const c=a(R(),"teams")+u;if(o===c.slice(0,-1)||o.startsWith(c))return{behavior:"allow",updatedInput:t,decisionReason:{type:"other",reason:"Team files are allowed for reading"}};const p=getBundledSkillsRoot()+u;return o.startsWith(p)?{behavior:"allow",updatedInput:t,decisionReason:{type:"other",reason:"Bundled skill reference files are allowed for reading"}}:{behavior:"passthrough",message:""}}
|