@iaforged/context-code 2.0.2 → 2.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/entrypoints/cli.js +1 -1
- package/dist/src/server/channelServer.js +1 -0
- package/dist/src/server/channelServer.test.js +1 -0
- package/dist/src/services/api/index.js +1 -1
- package/dist/src/utils/model/providers.js +1 -1
- package/dist/src/utils/sideQuery.js +1 -1
- package/dist/src/webapp/server.js +1 -1
- package/dist/webapp/ngsw.json +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
import{MACRO as e,feature as t}from"../recovery/bunBundleShim.js";if(process.env.COREPACK_ENABLE_AUTO_PIN="0",process.env.MAX_THINKING_TOKENS??="0","true"===process.env.CONTEXT_CODE_REMOTE||"true"===process.env.CLAUDE_CODE_REMOTE){const e=process.env.NODE_OPTIONS||"";process.env.NODE_OPTIONS=e?`${e} --max-old-space-size=8192`:"--max-old-space-size=8192"}if(t("ABLATION_BASELINE")&&(process.env.CONTEXT_CODE_ABLATION_BASELINE||process.env.CLAUDE_CODE_ABLATION_BASELINE))for(const e of["CLAUDE_CODE_SIMPLE","CONTEXT_CODE_SIMPLE","CLAUDE_CODE_DISABLE_THINKING","CONTEXT_CODE_DISABLE_THINKING","DISABLE_INTERLEAVED_THINKING","DISABLE_COMPACT","DISABLE_AUTO_COMPACT","CLAUDE_CODE_DISABLE_AUTO_MEMORY","CONTEXT_CODE_DISABLE_AUTO_MEMORY","CLAUDE_CODE_DISABLE_BACKGROUND_TASKS","CONTEXT_CODE_DISABLE_BACKGROUND_TASKS"])process.env[e]??="1";!async function(){const
|
|
1
|
+
import{MACRO as e,feature as t}from"../recovery/bunBundleShim.js";if(process.env.COREPACK_ENABLE_AUTO_PIN="0",process.env.MAX_THINKING_TOKENS??="0","true"===process.env.CONTEXT_CODE_REMOTE||"true"===process.env.CLAUDE_CODE_REMOTE){const e=process.env.NODE_OPTIONS||"";process.env.NODE_OPTIONS=e?`${e} --max-old-space-size=8192`:"--max-old-space-size=8192"}if(t("ABLATION_BASELINE")&&(process.env.CONTEXT_CODE_ABLATION_BASELINE||process.env.CLAUDE_CODE_ABLATION_BASELINE))for(const e of["CLAUDE_CODE_SIMPLE","CONTEXT_CODE_SIMPLE","CLAUDE_CODE_DISABLE_THINKING","CONTEXT_CODE_DISABLE_THINKING","DISABLE_INTERLEAVED_THINKING","DISABLE_COMPACT","DISABLE_AUTO_COMPACT","CLAUDE_CODE_DISABLE_AUTO_MEMORY","CONTEXT_CODE_DISABLE_AUTO_MEMORY","CLAUDE_CODE_DISABLE_BACKGROUND_TASKS","CONTEXT_CODE_DISABLE_BACKGROUND_TASKS"])process.env[e]??="1";!async function(){const r=process.argv.slice(2);if(1===r.length&&("--version"===r[0]||"-v"===r[0]||"-V"===r[0]))return void console.log(`${e.VERSION} (Context Code)`);const{profileCheckpoint:i}=await import("../utils/startupProfiler.js");if(i("cli_entry"),t("DUMP_SYSTEM_PROMPT")&&"--dump-system-prompt"===r[0]){i("cli_dump_system_prompt_path");const{enableConfigs:e}=await import("../utils/config.js");e();const{getMainLoopModel:t}=await import("../utils/model/model.js"),s=r.indexOf("--model"),a=-1!==s&&r[s+1]||t(),{getSystemPrompt:o}=await import("../constants/prompts.js"),n=await o([],a);return void console.log(n.join("\n"))}if("--claude-in-chrome-mcp"===process.argv[2]){i("cli_claude_in_chrome_mcp_path");const{runClaudeInChromeMcpServer:e}=await import("../utils/claudeInChrome/mcpServer.js");return void await e()}if("--chrome-native-host"===process.argv[2]){i("cli_chrome_native_host_path");const{runChromeNativeHost:e}=await import("../utils/claudeInChrome/chromeNativeHost.js");return void await e()}if(t("CHICAGO_MCP")&&"--computer-use-mcp"===process.argv[2]){i("cli_computer_use_mcp_path");const{runComputerUseMcpServer:e}=await import("../utils/computerUse/mcpServer.js");return void await e()}if("--database-mcp"===process.argv[2]){i("cli_database_mcp_path");const{runDatabaseMcpServer:e}=await import("../utils/databaseMcp/mcpServer.js");return void await e()}if("--ssh-mcp"===process.argv[2]){i("cli_ssh_mcp_path");const{runSshMcpServer:e}=await import("../utils/sshMcp/sshMcpServer.js");return void await e()}if("--remotion-mcp"===process.argv[2]){i("cli_remotion_mcp_path");const{runRemotionMcpServer:e}=await import("../utils/remotionMcp/mcpServer.js");return void await e()}if("--bridge-global-daemon"===process.argv[2]){i("cli_bridge_global_daemon_path");const{runGlobalBridgeDaemon:e}=await import("../bridgeGlobal/daemon.js");return void await e()}if("--headless"===process.argv[2]||"--json-channels"===process.argv[2]){i("cli_headless_channels_path");const{runHeadlessChannelServer:e}=await import("../server/channelServer.js"),t=process.argv.indexOf("--channel-port"),r=-1!==t&&process.argv[t+1]?parseInt(process.argv[t+1]):9878,s=process.argv.includes("--use-websocket")||process.argv.includes("--use-ws");return void await e({port:r,useWs:s})}if(t("DAEMON")&&"--daemon-worker"===r[0]){const{runDaemonWorker:e}=await import("../daemon/workerRegistry.js");return void await e(r[1])}if(t("BRIDGE_MODE")&&("remote-control"===r[0]||"rc"===r[0]||"remote"===r[0]||"sync"===r[0]||"bridge"===r[0])){i("cli_bridge_path");const{enableConfigs:e}=await import("../utils/config.js");e();const{getBridgeDisabledReason:t,checkBridgeMinVersion:s}=await import("../bridge/bridgeEnabled.js"),{BRIDGE_LOGIN_ERROR:a}=await import("../bridge/types.js"),{bridgeMain:o}=await import("../bridge/bridgeMain.js"),{exitWithError:n}=await import("../utils/process.js"),{getClaudeAIOAuthTokens:c}=await import("../utils/auth.js");c()?.accessToken||n(a);const l=await t();l&&n(`Error: ${l}`);const p=s();p&&n(p);const{waitForPolicyLimitsToLoad:_,isPolicyAllowed:m}=await import("../services/policyLimits/index.js");return await _(),m("allow_remote_control")||n("Error: Remote Control is disabled by your organization's policy."),void await o(r.slice(1))}if(t("DAEMON")&&"daemon"===r[0]){i("cli_daemon_path");const{enableConfigs:e}=await import("../utils/config.js");e();const{initSinks:t}=await import("../utils/sinks.js");t();const{daemonMain:s}=await import("../daemon/main.js");return void await s(r.slice(1))}if(t("BG_SESSIONS")&&("ps"===r[0]||"logs"===r[0]||"attach"===r[0]||"kill"===r[0]||r.includes("--bg")||r.includes("--background"))){i("cli_bg_path");const{enableConfigs:e}=await import("../utils/config.js");e();const t=await import("../cli/bg.js");switch(r[0]){case"ps":await t.psHandler(r.slice(1));break;case"logs":await t.logsHandler(r[1]);break;case"attach":await t.attachHandler(r[1]);break;case"kill":await t.killHandler(r[1]);break;default:await t.handleBgFlag(r)}return}if(t("TEMPLATES")&&("new"===r[0]||"list"===r[0]||"reply"===r[0])){i("cli_templates_path");const{templatesMain:e}=await import("../cli/handlers/templateJobs.js");await e(r),process.exit(0)}if(t("BYOC_ENVIRONMENT_RUNNER")&&"environment-runner"===r[0]){i("cli_environment_runner_path");const{environmentRunnerMain:e}=await import("../environment-runner/main.js");return void await e(r.slice(1))}if(t("SELF_HOSTED_RUNNER")&&"self-hosted-runner"===r[0]){i("cli_self_hosted_runner_path");const{selfHostedRunnerMain:e}=await import("../self-hosted-runner/main.js");return void await e(r.slice(1))}if((r.includes("--tmux")||r.includes("--tmux=classic"))&&(r.includes("-w")||r.includes("--worktree")||r.some(e=>e.startsWith("--worktree=")))){i("cli_tmux_worktree_fast_path");const{enableConfigs:e}=await import("../utils/config.js");e();const{isWorktreeModeEnabled:t}=await import("../utils/worktreeModeEnabled.js");if(t()){const{execIntoTmuxWorktree:e}=await import("../utils/worktree.js"),t=await e(r);if(t.handled)return;if(t.error){const{exitWithError:e}=await import("../utils/process.js");e(t.error)}}}1!==r.length||"--update"!==r[0]&&"--upgrade"!==r[0]||(process.argv=[process.argv[0],process.argv[1],"update"]),r.includes("--bare")&&(process.env.CLAUDE_CODE_SIMPLE="1");const{startCapturingEarlyInput:s}=await import("../utils/earlyInput.js");s(),i("cli_before_main_import");const{main:a}=await import("../main.js");i("cli_after_main_import"),await a(),i("cli_after_main_complete")}();
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{createInterface as e}from"node:readline";import{WebSocketServer as t}from"ws";import{QueryEngine as s}from"../QueryEngine.js";import{getTools as o}from"../tools.js";import{getCommands as a}from"../commands.js";import{getSessionId as r}from"../bootstrap/state.js";import{createStore as n}from"../state/store.js";import{getDefaultAppState as i}from"../state/AppStateStore.js";import{cloneFileStateCache as l}from"../utils/fileStateCache.js";import{createAbortController as c}from"../utils/abortController.js";import*as d from"../webapp/server.js";class Deferred{promise;resolve;reject;constructor(){this.promise=new Promise((e,t)=>{this.resolve=e,this.reject=t})}}let h=null;export function getActiveHeadlessServer(){return h}export class HeadlessChannelServer{engine=null;wsServer=null;activeWsClients=new Set;activeToolResolver=null;abortController=null;currentCwd=process.cwd();constructor(){h=this}async start(s={}){if(e({input:process.stdin,output:process.stdout,terminal:!1}).on("line",e=>{this.handleInputLine(e.trim())}),s.useWs){const e=s.port||9878;this.wsServer=new t({port:e,host:"127.0.0.1"}),this.wsServer.on("connection",e=>{this.activeWsClients.add(e),this.sendToChannel({type:"channel_connected",message:"Conexión establecida con el canal Headles WebSocket."},e),e.on("message",e=>{this.handleInputLine(e.toString().trim())}),e.on("close",()=>{this.activeWsClients.delete(e)})}),console.error(`[Headless Channel Server] WebSocket escuchando en ws://127.0.0.1:${e}`)}console.error("[Headless Channel Server] Inicializado en stdio (JSONLines). Esperando start_session...")}async handleInputLine(e){if(e)try{const t=JSON.parse(e);switch(t.type){case"start_session":await this.handleStartSession(t);break;case"submit_prompt":await this.handleSubmitPrompt(t);break;case"approve_tool":this.handleApproveTool(t);break;case"reject_tool":this.handleRejectTool(t);break;case"abort":this.handleAbort();break;default:this.sendError(`Tipo de comando desconocido: ${t.type}`)}}catch(e){this.sendError(`Error al procesar línea JSON: ${e.message}`)}}async handleStartSession(e){const t=e.cwd||process.cwd();this.currentCwd=t;try{const d=n(i()),h=d.getState(),p=o(h.toolPermissionContext),m=await a(t);this.abortController=c(),this.engine=new s({cwd:t,tools:p,commands:m,mcpClients:h.mcp.clients.map(e=>e.config),agents:[],canUseTool:this.makeInteractiveCanUseTool(),getAppState:()=>d.getState(),setAppState:e=>d.setState(e),readFileCache:l(h.readFileCache),abortController:this.abortController,userSpecifiedModel:e.options?.model}),this.sendToChannel({type:"session_created",session_id:r(),status:"idle",cwd:t})}catch(e){this.sendError(`Fallo al inicializar sesión Headless: ${e.message}`)}}makeInteractiveCanUseTool(){return async(e,t,s,o,a,r)=>{this.activeToolResolver&&this.activeToolResolver.reject(new Error("Turno interrumpido por nueva solicitud de herramienta.")),this.activeToolResolver=new Deferred,this.sendToChannel({type:"tool_call",tool_use_id:a,tool_name:e.name,arguments:t,description:e.description}),d.broadcastPermission({id:a,toolName:e.name,arguments:t,description:e.description});try{return await this.activeToolResolver.promise}finally{this.activeToolResolver=null}}}async handleSubmitPrompt(e){const t=e.text;t?await this.handleSubmitPromptDirect(t,e.uuid):this.sendError('El campo "text" es requerido para enviar un prompt.')}async handleSubmitPromptDirect(e,t){if(this.engine||await this.handleStartSession({cwd:this.currentCwd}),this.engine){this.abortController&&!this.abortController.signal.aborted||(this.abortController=c());try{this.sendToChannel({type:"status_change",status:"thinking"});const s=this.engine.submitMessage(e,{uuid:t});for await(const e of s)this.sendToChannel(e),this.broadcastHeadlessMessageToWebapp(e)}catch(e){this.sendToChannel({type:"session_ended",is_error:!0,error:e.message}),d.broadcastStatus(!1),d.broadcastThinking("",!1)}}else this.sendError("No se pudo inicializar la sesión del motor headless.")}handleApproveTool(e){this.activeToolResolver?(this.activeToolResolver.resolve({behavior:"allow"}),this.sendToChannel({type:"tool_approved",tool_use_id:e.tool_use_id}),d.broadcastPermissionResolved(e.tool_use_id,"approved","webapp")):this.sendError("No hay ninguna confirmación de herramienta pendiente.")}handleRejectTool(e){this.activeToolResolver?(this.activeToolResolver.resolve({behavior:"deny"}),this.sendToChannel({type:"tool_rejected",tool_use_id:e.tool_use_id}),d.broadcastPermissionResolved(e.tool_use_id,"rejected","webapp")):this.sendError("No hay ninguna confirmación de herramienta pendiente.")}handleAbort(){this.abortController?(this.abortController.abort(),this.sendToChannel({type:"aborted",message:"Inferencia cancelada por el cliente."}),d.broadcastStatus(!1),d.broadcastThinking("",!1)):this.sendError("No hay ninguna tarea activa para cancelar.")}broadcastHeadlessMessageToWebapp(e){"assistant"===e.type&&e.message&&"string"==typeof e.message.content&&d.broadcastMessage("assistant",e.message.content),"user"===e.type&&e.message&&"string"==typeof e.message.content&&d.broadcastMessage("user",e.message.content),"status"===e.type&&("thinking"===e.status?(d.broadcastThinking("Pensando...",!0),d.broadcastStatus(!0)):"done"===e.status&&(d.broadcastStatus(!1),d.broadcastThinking("",!1))),"result"===e.type&&(d.broadcastStatus(!1),d.broadcastThinking("",!1),e.result&&d.broadcastMessage("assistant",e.result))}sendToChannel(e,t){const s=JSON.stringify(e);if(process.stdout.write(s+"\n"),t)t.readyState===WebSocket.OPEN&&t.send(s);else for(const e of this.activeWsClients)e.readyState===WebSocket.OPEN&&e.send(s)}sendError(e){this.sendToChannel({type:"channel_error",message:e})}}export async function runHeadlessChannelServer(e={}){const t=new HeadlessChannelServer;await t.start(e)}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import e from"node:assert";import{HeadlessChannelServer as o}from"./channelServer.js";console.log("🧪 Iniciando pruebas unitarias de HeadlessChannelServer..."),async function(){try{const t=new o;e.strictEqual(typeof t.start,"function","El método start debe ser una función"),e.strictEqual(typeof t.handleSubmitPromptDirect,"function","El método handleSubmitPromptDirect debe ser una función"),console.log("✅ Test 1 aprobado: HeadlessChannelServer instanciado correctamente.");const n=process.stdout.write,a=[];process.stdout.write=e=>(a.push(e.toString()),!0);try{await t.handleInputLine('{"type": "unknown_action"}'),e.ok(a.length>0,"Debe emitir al menos un evento en la salida estándar");const o=JSON.parse(a[0].trim());e.strictEqual(o.type,"channel_error","Debe emitir un channel_error ante acciones desconocidas"),console.log("✅ Test 2 aprobado: Control de excepciones del protocolo JSONLines validado con éxito.")}finally{process.stdout.write=n}console.log("🔒 Verificando flujo diferido de aprobación de herramientas..."),e.strictEqual(typeof t.handleApproveTool,"function","handleApproveTool debe estar expuesto"),e.strictEqual(typeof t.handleRejectTool,"function","handleRejectTool debe estar expuesto"),e.strictEqual(typeof t.handleAbort,"function","handleAbort debe estar expuesto"),console.log("✅ Test 3 aprobado: El ciclo de promesas de seguridad diferida está correctamente expuesto."),console.log("\n🎉 ¡Todas las pruebas unitarias de Headless pasaron con éxito impecable! 🎉"),process.exit(0)}catch(e){console.error("❌ Fallo en las pruebas unitarias de Headless:",e.message),process.exit(1)}}();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{getAPIProvider as o,
|
|
1
|
+
import{getAPIProvider as o,usesOpenAIBackend as s}from"../../utils/model/providers.js";import{queryModelWithStreaming as i}from"./claude.js";import{queryOpenAIModelWithStreaming as t}from"./openai.js";export async function*queryModelWithStreaming({messages:e,systemPrompt:n,thinkingConfig:m,tools:r,signal:g,options:l}){return s(o())?yield*t({messages:e,systemPrompt:n,thinkingConfig:m,tools:r,signal:g,options:l}):yield*i({messages:e,systemPrompt:n,thinkingConfig:m,tools:r,signal:g,options:l})}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{isEnvTruthy as e}from"../envUtils.js";import{getSecureStorage as r}from"../secureStorage/index.js";import{isProviderBaseUrlCustomized as o}from"./providerBaseUrls.js";import{getProviderOverride as i}from"./providerOverrideContext.js";import{getStoredActiveProviderPreference as n}from"./providerProfilesDb.js";import{listProviderProfiles as t}from"./providerProfiles.js";export function providerPreferenceToApiProvider(e){if(e)return"claude"===e?"firstParty":e}export function isOpenAIProviderConfigured(){return e(process.env.CLAUDE_CODE_USE_OPENAI)||Boolean(process.env.OPENAI_API_KEY)||Boolean(process.env.OPENAI_API_TOKEN)||Boolean(process.env.OPENAI_OAUTH_TOKEN)||function(){try{const e=r().read(),o=Object.entries(e?.providerProfileOauth??{}).some(([e,r])=>e.startsWith("openai/")&&"object"==typeof r&&null!==r&&"string"==typeof r.accessToken&&r.accessToken.trim());return Boolean(o||e?.openAiOauth?.accessToken)}catch{return!1}}()}export function isOpenRouterProviderConfigured(){try{const e=r().read(),o=Object.entries(e?.providerProfileApiKeys??{}).some(([e,r])=>e.startsWith("openrouter/")&&"string"==typeof r&&r.trim());return Boolean(process.env.OPENROUTER_API_KEY||process.env.OPENROUTER_API_TOKEN||e?.providerApiKeys?.openrouter||o)}catch{return Boolean(process.env.OPENROUTER_API_KEY||process.env.OPENROUTER_API_TOKEN)}}export function isOllamaProviderConfigured(){try{const e=n();return Boolean(process.env.OLLAMA_BASE_URL||o("ollama")||t("ollama").length>0||"ollama"===e)}catch{return Boolean(process.env.OLLAMA_BASE_URL)}}export function isOllamaCloudProviderConfigured(){if(isOllamaProviderConfigured())return!0;try{const e=r().read(),i=Object.entries(e?.providerProfileApiKeys??{}).some(([e,r])=>e.startsWith("ollama-cloud/")&&"string"==typeof r&&r.trim()),t=n();return Boolean(process.env.OLLAMA_CLOUD_BASE_URL||process.env.OLLAMA_BASE_URL||process.env.OLLAMA_API_KEY||e?.providerApiKeys?.["ollama-cloud"]||i||o("ollama-cloud")||"ollama-cloud"===t||"ollama"===t)}catch{return Boolean(process.env.OLLAMA_CLOUD_BASE_URL||process.env.OLLAMA_BASE_URL||process.env.OLLAMA_API_KEY)}}export function isGeminiApiProviderConfigured(){try{const e=r().read(),o=Object.entries(e?.providerProfileApiKeys??{}).some(([e,r])=>e.startsWith("gemini-api/")&&"string"==typeof r&&r.trim());return Boolean(process.env.GEMINI_API_KEY||process.env.GOOGLE_API_KEY||e?.providerApiKeys?.["gemini-api"]||o)}catch{return Boolean(process.env.GEMINI_API_KEY||process.env.GOOGLE_API_KEY)}}export function isGeminiGoogleProviderConfigured(){try{const e=n();return Boolean(process.env.GEMINI_OAUTH_TOKEN||process.env.GOOGLE_OAUTH_ACCESS_TOKEN||process.env.GOOGLE_APPLICATION_CREDENTIALS||process.env.GEMINI_GOOGLE_PROJECT_ID||process.env.GOOGLE_CLOUD_PROJECT||process.env.GCLOUD_PROJECT||Object.entries(storage?.providerProfileOauth??{}).some(([e,r])=>e.startsWith("gemini-google/")&&"object"==typeof r&&null!==r&&"string"==typeof r.accessToken&&r.accessToken.trim())||"gemini-google"===e)}catch{return Boolean(process.env.GEMINI_OAUTH_TOKEN||process.env.GOOGLE_OAUTH_ACCESS_TOKEN||process.env.GOOGLE_APPLICATION_CREDENTIALS||process.env.GEMINI_GOOGLE_PROJECT_ID||process.env.GOOGLE_CLOUD_PROJECT||process.env.GCLOUD_PROJECT)}}export function isZAIProviderConfigured(){try{const e=r().read(),o=Object.entries(e?.providerProfileApiKeys??{}).some(([e,r])=>e.startsWith("zai/")&&"string"==typeof r&&r.trim());return Boolean(process.env.ZAI_API_KEY||e?.providerApiKeys?.zai||o)}catch{return Boolean(process.env.ZAI_API_KEY)}}export function isMiniMaxProviderConfigured(){try{const e=r().read(),o=Object.entries(e?.providerProfileApiKeys??{}).some(([e,r])=>e.startsWith("minimax/")&&"string"==typeof r&&r.trim());return Boolean(process.env.MINIMAX_API_KEY||e?.providerApiKeys?.minimax||o)}catch{return Boolean(process.env.MINIMAX_API_KEY)}}export function isNvidiaProviderConfigured(){try{const e=r().read(),o=Object.entries(e?.providerProfileApiKeys??{}).some(([e,r])=>e.startsWith("nvidia/")&&"string"==typeof r&&r.trim());return Boolean(process.env.NVIDIA_API_KEY||e?.providerApiKeys?.nvidia||o)}catch{return Boolean(process.env.NVIDIA_API_KEY)}}export function isDeepSeekProviderConfigured(){try{const e=r().read(),o=Object.entries(e?.providerProfileApiKeys??{}).some(([e,r])=>e.startsWith("deepseek/")&&"string"==typeof r&&r.trim());return Boolean(process.env.DEEPSEEK_API_KEY||e?.providerApiKeys?.deepseek||o)}catch{return Boolean(process.env.DEEPSEEK_API_KEY)}}export function isOpenAICompatibleProvider(e){return"openai"===e||"openrouter"===e||"ollama"===e||"ollama-cloud"===e||"gemini-api"===e||"gemini-google"===e||"zai"===e||"minimax"===e||"nvidia"===e||"deepseek"===e}export function hasDualProviderSessions(){return(isOpenAIProviderConfigured()||isOpenRouterProviderConfigured()||isOllamaProviderConfigured()||isOllamaCloudProviderConfigured()||isGeminiApiProviderConfigured()||isGeminiGoogleProviderConfigured()||isZAIProviderConfigured()||isMiniMaxProviderConfigured()||isNvidiaProviderConfigured()||isDeepSeekProviderConfigured())&&function(){try{const e=r().read(),o=Object.entries(e?.providerProfileOauth??{}).some(([e,r])=>e.startsWith("claude/")&&"object"==typeof r&&null!==r&&"string"==typeof r.accessToken&&r.accessToken.trim());return Boolean(o)}catch{return!1}}()}export function getAPIProvider(){const r=i();if(r)return r;if(e(process.env.CLAUDE_CODE_USE_BEDROCK))return"bedrock";if(e(process.env.CLAUDE_CODE_USE_VERTEX))return"vertex";if(e(process.env.CLAUDE_CODE_USE_FOUNDRY))return"foundry";try{const e=n();if("claude"===e)return"firstParty";if("openai"===e)return"openai";if("openrouter"===e)return"openrouter";if("ollama"===e)return"ollama";if("ollama-cloud"===e)return"ollama-cloud";if("gemini-api"===e)return"gemini-api";if("gemini-google"===e)return"gemini-google";if("zai"===e)return"zai";if("minimax"===e)return"minimax";if("nvidia"===e)return"nvidia";if("deepseek"===e)return"deepseek"}catch{}const o=isOpenAIProviderConfigured(),t=isOpenRouterProviderConfigured(),s=isOllamaProviderConfigured(),a=isOllamaCloudProviderConfigured(),p=isGeminiApiProviderConfigured(),c=isGeminiGoogleProviderConfigured(),d=isZAIProviderConfigured(),u=isMiniMaxProviderConfigured(),l=isNvidiaProviderConfigured(),v=isDeepSeekProviderConfigured();return o?"openai":t?"openrouter":d?"zai":u?"minimax":l?"nvidia":v?"deepseek":p?"gemini-api":c?"gemini-google":a?"ollama-cloud":s?"ollama":"firstParty"}export function getAPIProviderForStatsig(){return getAPIProvider()}export function isFirstPartyAnthropicBaseUrl(){const e=process.env.ANTHROPIC_BASE_URL;if(!e)return!0;try{const r=new URL(e).host,o=["api.anthropic.com"];return"ant"===process.env.USER_TYPE&&o.push("api-staging.anthropic.com"),o.includes(r)}catch{return!1}}
|
|
1
|
+
import{isEnvTruthy as e}from"../envUtils.js";import{getSecureStorage as r}from"../secureStorage/index.js";import{isProviderBaseUrlCustomized as o}from"./providerBaseUrls.js";import{getProviderOverride as i}from"./providerOverrideContext.js";import{getStoredActiveProviderPreference as n}from"./providerProfilesDb.js";import{listProviderProfiles as t}from"./providerProfiles.js";export function providerPreferenceToApiProvider(e){if(e)return"claude"===e?"firstParty":e}export function isOpenAIProviderConfigured(){return e(process.env.CLAUDE_CODE_USE_OPENAI)||Boolean(process.env.OPENAI_API_KEY)||Boolean(process.env.OPENAI_API_TOKEN)||Boolean(process.env.OPENAI_OAUTH_TOKEN)||function(){try{const e=r().read(),o=Object.entries(e?.providerProfileOauth??{}).some(([e,r])=>e.startsWith("openai/")&&"object"==typeof r&&null!==r&&"string"==typeof r.accessToken&&r.accessToken.trim());return Boolean(o||e?.openAiOauth?.accessToken)}catch{return!1}}()}export function isOpenRouterProviderConfigured(){try{const e=r().read(),o=Object.entries(e?.providerProfileApiKeys??{}).some(([e,r])=>e.startsWith("openrouter/")&&"string"==typeof r&&r.trim());return Boolean(process.env.OPENROUTER_API_KEY||process.env.OPENROUTER_API_TOKEN||e?.providerApiKeys?.openrouter||o)}catch{return Boolean(process.env.OPENROUTER_API_KEY||process.env.OPENROUTER_API_TOKEN)}}export function isOllamaProviderConfigured(){try{const e=n();return Boolean(process.env.OLLAMA_BASE_URL||o("ollama")||t("ollama").length>0||"ollama"===e)}catch{return Boolean(process.env.OLLAMA_BASE_URL)}}export function isOllamaCloudProviderConfigured(){if(isOllamaProviderConfigured())return!0;try{const e=r().read(),i=Object.entries(e?.providerProfileApiKeys??{}).some(([e,r])=>e.startsWith("ollama-cloud/")&&"string"==typeof r&&r.trim()),t=n();return Boolean(process.env.OLLAMA_CLOUD_BASE_URL||process.env.OLLAMA_BASE_URL||process.env.OLLAMA_API_KEY||e?.providerApiKeys?.["ollama-cloud"]||i||o("ollama-cloud")||"ollama-cloud"===t||"ollama"===t)}catch{return Boolean(process.env.OLLAMA_CLOUD_BASE_URL||process.env.OLLAMA_BASE_URL||process.env.OLLAMA_API_KEY)}}export function isGeminiApiProviderConfigured(){try{const e=r().read(),o=Object.entries(e?.providerProfileApiKeys??{}).some(([e,r])=>e.startsWith("gemini-api/")&&"string"==typeof r&&r.trim());return Boolean(process.env.GEMINI_API_KEY||process.env.GOOGLE_API_KEY||e?.providerApiKeys?.["gemini-api"]||o)}catch{return Boolean(process.env.GEMINI_API_KEY||process.env.GOOGLE_API_KEY)}}export function isGeminiGoogleProviderConfigured(){try{const e=n();return Boolean(process.env.GEMINI_OAUTH_TOKEN||process.env.GOOGLE_OAUTH_ACCESS_TOKEN||process.env.GOOGLE_APPLICATION_CREDENTIALS||process.env.GEMINI_GOOGLE_PROJECT_ID||process.env.GOOGLE_CLOUD_PROJECT||process.env.GCLOUD_PROJECT||Object.entries(storage?.providerProfileOauth??{}).some(([e,r])=>e.startsWith("gemini-google/")&&"object"==typeof r&&null!==r&&"string"==typeof r.accessToken&&r.accessToken.trim())||"gemini-google"===e)}catch{return Boolean(process.env.GEMINI_OAUTH_TOKEN||process.env.GOOGLE_OAUTH_ACCESS_TOKEN||process.env.GOOGLE_APPLICATION_CREDENTIALS||process.env.GEMINI_GOOGLE_PROJECT_ID||process.env.GOOGLE_CLOUD_PROJECT||process.env.GCLOUD_PROJECT)}}export function isZAIProviderConfigured(){try{const e=r().read(),o=Object.entries(e?.providerProfileApiKeys??{}).some(([e,r])=>e.startsWith("zai/")&&"string"==typeof r&&r.trim());return Boolean(process.env.ZAI_API_KEY||e?.providerApiKeys?.zai||o)}catch{return Boolean(process.env.ZAI_API_KEY)}}export function isMiniMaxProviderConfigured(){try{const e=r().read(),o=Object.entries(e?.providerProfileApiKeys??{}).some(([e,r])=>e.startsWith("minimax/")&&"string"==typeof r&&r.trim());return Boolean(process.env.MINIMAX_API_KEY||e?.providerApiKeys?.minimax||o)}catch{return Boolean(process.env.MINIMAX_API_KEY)}}export function isNvidiaProviderConfigured(){try{const e=r().read(),o=Object.entries(e?.providerProfileApiKeys??{}).some(([e,r])=>e.startsWith("nvidia/")&&"string"==typeof r&&r.trim());return Boolean(process.env.NVIDIA_API_KEY||e?.providerApiKeys?.nvidia||o)}catch{return Boolean(process.env.NVIDIA_API_KEY)}}export function isDeepSeekProviderConfigured(){try{const e=r().read(),o=Object.entries(e?.providerProfileApiKeys??{}).some(([e,r])=>e.startsWith("deepseek/")&&"string"==typeof r&&r.trim());return Boolean(process.env.DEEPSEEK_API_KEY||e?.providerApiKeys?.deepseek||o)}catch{return Boolean(process.env.DEEPSEEK_API_KEY)}}export function isOpenAICompatibleProvider(e){return"openai"===e||"openrouter"===e||"ollama"===e||"ollama-cloud"===e||"gemini-api"===e||"gemini-google"===e||"zai"===e||"minimax"===e||"nvidia"===e||"deepseek"===e}export function usesOpenAIBackend(e){return isOpenAICompatibleProvider(e)&&"minimax"!==e}export function hasDualProviderSessions(){return(isOpenAIProviderConfigured()||isOpenRouterProviderConfigured()||isOllamaProviderConfigured()||isOllamaCloudProviderConfigured()||isGeminiApiProviderConfigured()||isGeminiGoogleProviderConfigured()||isZAIProviderConfigured()||isMiniMaxProviderConfigured()||isNvidiaProviderConfigured()||isDeepSeekProviderConfigured())&&function(){try{const e=r().read(),o=Object.entries(e?.providerProfileOauth??{}).some(([e,r])=>e.startsWith("claude/")&&"object"==typeof r&&null!==r&&"string"==typeof r.accessToken&&r.accessToken.trim());return Boolean(o)}catch{return!1}}()}export function getAPIProvider(){const r=i();if(r)return r;if(e(process.env.CLAUDE_CODE_USE_BEDROCK))return"bedrock";if(e(process.env.CLAUDE_CODE_USE_VERTEX))return"vertex";if(e(process.env.CLAUDE_CODE_USE_FOUNDRY))return"foundry";try{const e=n();if("claude"===e)return"firstParty";if("openai"===e)return"openai";if("openrouter"===e)return"openrouter";if("ollama"===e)return"ollama";if("ollama-cloud"===e)return"ollama-cloud";if("gemini-api"===e)return"gemini-api";if("gemini-google"===e)return"gemini-google";if("zai"===e)return"zai";if("minimax"===e)return"minimax";if("nvidia"===e)return"nvidia";if("deepseek"===e)return"deepseek"}catch{}const o=isOpenAIProviderConfigured(),t=isOpenRouterProviderConfigured(),s=isOllamaProviderConfigured(),a=isOllamaCloudProviderConfigured(),p=isGeminiApiProviderConfigured(),c=isGeminiGoogleProviderConfigured(),d=isZAIProviderConfigured(),u=isMiniMaxProviderConfigured(),l=isNvidiaProviderConfigured(),v=isDeepSeekProviderConfigured();return o?"openai":t?"openrouter":d?"zai":u?"minimax":l?"nvidia":v?"deepseek":p?"gemini-api":c?"gemini-google":a?"ollama-cloud":s?"ollama":"firstParty"}export function getAPIProviderForStatsig(){return getAPIProvider()}export function isFirstPartyAnthropicBaseUrl(){const e=process.env.ANTHROPIC_BASE_URL;if(!e)return!0;try{const r=new URL(e).host,o=["api.anthropic.com"];return"ant"===process.env.USER_TYPE&&o.push("api-staging.anthropic.com"),o.includes(r)}catch{return!1}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{MACRO as e}from"../recovery/bunBundleShim.js";import{getLastApiCompletionTimestamp as t,setLastApiCompletionTimestamp as s}from"../bootstrap/state.js";import{STRUCTURED_OUTPUTS_BETA_HEADER as o}from"../constants/betas.js";import{getAttributionHeader as n,getCLISyspromptPrefix as i}from"../constants/system.js";import{logEvent as r}from"../services/analytics/index.js";import{getAPIMetadata as a}from"../services/api/claude.js";import{getAnthropicClient as u}from"../services/api/client.js";import{queryOpenAISideQuery as p}from"../services/api/openai.js";import{getModelBetas as c,modelSupportsStructuredOutputs as m}from"./betas.js";import{computeFingerprint as d}from"./fingerprint.js";import{normalizeModelStringForAPI as l}from"./model/model.js";import{getAPIProvider as _,
|
|
1
|
+
import{MACRO as e}from"../recovery/bunBundleShim.js";import{getLastApiCompletionTimestamp as t,setLastApiCompletionTimestamp as s}from"../bootstrap/state.js";import{STRUCTURED_OUTPUTS_BETA_HEADER as o}from"../constants/betas.js";import{getAttributionHeader as n,getCLISyspromptPrefix as i}from"../constants/system.js";import{logEvent as r}from"../services/analytics/index.js";import{getAPIMetadata as a}from"../services/api/claude.js";import{getAnthropicClient as u}from"../services/api/client.js";import{queryOpenAISideQuery as p}from"../services/api/openai.js";import{getModelBetas as c,modelSupportsStructuredOutputs as m}from"./betas.js";import{computeFingerprint as d}from"./fingerprint.js";import{normalizeModelStringForAPI as l}from"./model/model.js";import{getAPIProvider as _,usesOpenAIBackend as y}from"./model/providers.js";export async function sideQuery(g){const{model:f,system:k,messages:h,tools:x,tool_choice:j,output_format:v,max_tokens:q=1024,maxRetries:I=2,signal:S,skipSystemPromptPrefix:b,temperature:T,thinking:w,stop_sequences:A}=g,M=[...c(f)];v&&m(f)&&!M.includes(o)&&M.push(o);const R=function(e){const t=e.find(e=>"user"===e.role);if(!t)return"";const s=t.content;if("string"==typeof s)return s;const o=s.find(e=>"text"===e.type);return"text"===o?.type?o.text:""}(h),P=d(R,e.VERSION),C=n(P),D=[C?{type:"text",text:C}:null,...b?[]:[{type:"text",text:i({isNonInteractive:!1,hasAppendSystemPrompt:!1})}],...Array.isArray(k)?k:k?[{type:"text",text:k}]:[]].filter(e=>null!==e);let L;!1===w?L={type:"disabled"}:void 0!==w&&(L={type:"enabled",budget_tokens:Math.min(w,q-1)});const N=l(f),O=Date.now();if(y(_())){const e=await p({model:N,systemPrompt:D.map(e=>e.text).join("\n\n"),messages:h.map(e=>({role:e.role,content:"string"==typeof e.content?e.content:e.content.filter(e=>"text"===e.type&&"string"==typeof e.text).map(e=>({type:"text",text:e.text}))})),tools:x?.map(e=>({name:e.name,description:e.description,input_schema:e.input_schema})),toolChoice:j,outputFormat:"json_schema"===v?.type?{type:"json_schema",schema:v.schema}:void 0,signal:S,maxOutputTokens:q,temperature:T}),o=Date.now(),n=t();return r("tengu_api_success",{requestId:e.id,querySource:g.querySource,model:N,inputTokens:e.usage?.input_tokens??0,outputTokens:e.usage?.output_tokens??0,cachedInputTokens:0,uncachedInputTokens:0,durationMsIncludingRetries:o-O,timeSinceLastApiCallMs:null!==n?o-n:void 0}),s(o),{id:e.id??"",type:"message",role:"assistant",model:N,content:e.content,stop_reason:"end_turn",stop_sequence:null,usage:{input_tokens:e.usage?.input_tokens??0,output_tokens:e.usage?.output_tokens??0,cache_creation_input_tokens:0,cache_read_input_tokens:0}}}const B=await u({maxRetries:I,model:f,source:"side_query"}),E=await B.beta.messages.create({model:N,max_tokens:q,system:D,messages:h,...x&&{tools:x},...j&&{tool_choice:j},...v&&{output_config:{format:v}},...void 0!==T&&{temperature:T},...A&&{stop_sequences:A},...L&&{thinking:L},...M.length>0&&{betas:M},metadata:a()},{signal:S}),F=E._request_id??void 0,Q=Date.now(),V=t();return r("tengu_api_success",{requestId:F,querySource:g.querySource,model:N,inputTokens:E.usage.input_tokens,outputTokens:E.usage.output_tokens,cachedInputTokens:E.usage.cache_read_input_tokens??0,uncachedInputTokens:E.usage.cache_creation_input_tokens??0,durationMsIncludingRetries:Q-O,timeSinceLastApiCallMs:null!==V?Q-V:void 0}),s(Q),E}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createServer as e}from"node:http";import{existsSync as t,statSync as o,createReadStream as r}from"node:fs";import{extname as a,join as s,resolve as i,sep as n}from"node:path";import{dirname as c}from"node:path";import{fileURLToPath as p}from"node:url";import{randomUUID as l}from"node:crypto";import{WebSocketServer as d}from"ws";import{getGlobalConfig as u}from"../utils/config.js";import{logForDebugging as m}from"../utils/debug.js";import{logError as f}from"../utils/log.js";import{MACRO as b}from"../recovery/bunBundleShim.js";import{ensureWebappToken as g,tokenMatches as v}from"./auth.js";import{stopTunnel as w}from"./tunnel.js";import{PROTOCOL_VERSION as h}from"./protocol.js";import{listSessionsImpl as y}from"../utils/listSessionsImpl.js";import{getOriginalCwd as S}from"../bootstrap/state.js";import{getAPIProvider as W}from"../utils/model/providers.js";import{setStoredActiveProviderPreference as k,getStoredLastModelForProvider as x,setStoredLastModelForProvider as C}from"../utils/model/providerProfilesDb.js";import{fetchProviderModels as P}from"../utils/model/providerModels.js";import{getModelOptions as j}from"../utils/model/modelOptions.js";import{getWorktreePaths as _}from"../utils/getWorktreePaths.js";import{getGlobalBridgeDaemonStatus as L,startGlobalBridgeDaemon as E,stopGlobalBridgeDaemon as $}from"../bridgeGlobal/manager.js";import{readSelfIdentity as I}from"../whatsapp/session.js";import{getWhatsAppAuthDir as A}from"../whatsapp/config.js";import{startLoginWithQr as N}from"../whatsapp/bridge.js";import{enqueue as O}from"../utils/messageQueueManager.js";import{markInjected as T}from"../mirrors/shared.js";let H=null,R=null;const U=new Set,D=new Set,M=[],G=l();let J={},V=null,z=null,q=null;export function broadcastInteractiveSelect(e,t,o,r,a){return new Promise((s,i)=>{if(!isWebappRunning()||0===U.size)return void i(new Error("WebApp no está activa o no hay clientes conectados."));z&&(clearTimeout(z.timeout),z.reject(new Error("Interrumpido por una nueva selección interactiva.")),z=null);const n=setTimeout(()=>{z&&z.id===e&&(z.reject(new Error("Timeout esperando selección del usuario en la WebApp.")),z=null)},3e5);z={id:e,resolve:s,reject:i,timeout:n},fanout({type:"interactive_select",id:e,title:t,description:r,options:o,defaultValue:a})})}export function broadcastInteractiveInput(e,t,o,r,a,s){return new Promise((i,n)=>{if(!isWebappRunning()||0===U.size)return void n(new Error("WebApp no está activa o no hay clientes conectados."));q&&(clearTimeout(q.timeout),q.reject(new Error("Interrumpido por una nueva entrada de texto interactiva.")),q=null);const c=setTimeout(()=>{q&&q.id===e&&(q.reject(new Error("Timeout esperando entrada de texto del usuario en la WebApp.")),q=null)},3e5);q={id:e,resolve:i,reject:n,timeout:c},fanout({type:"interactive_input",id:e,title:t,description:o,placeholder:r,mask:a,defaultValue:s})})}let B=null,F=null;export function setWebappHandlers(e){J={...J,...e}}export function isWebappRunning(){return null!==H}export function getWebappPort(){return u().webappConfig?.port??9876}export function getWebappBindHost(){return u().webappConfig?.bindHost??"127.0.0.1"}export function getWebappPublicUrl(){return u().webappConfig?.publicUrl??null}export function getWebappUrl(){const e=g(),t=getWebappPublicUrl();if(t){const o=t.replace(/\/+$/,""),r=o.includes("?")?"&":"?";return`${o}/${r}token=${e}`.replace(/\/\?/,"/?")}return`http://localhost:${getWebappPort()}/?token=${e}`}export function getWebappLocalUrl(){const e=g();return`http://localhost:${getWebappPort()}/?token=${e}`}export function getWebappStatus(){const e=resolveStaticDir();return{running:isWebappRunning(),port:isWebappRunning()?getWebappPort():void 0,url:isWebappRunning()?getWebappUrl():void 0,localUrl:isWebappRunning()?getWebappLocalUrl():void 0,publicUrl:getWebappPublicUrl(),bindHost:isWebappRunning()?getWebappBindHost():void 0,connections:U.size,sessionId:isWebappRunning()?G:void 0,staticDir:e,staticAvailable:Boolean(e)}}export async function startWebappServer(){if(H)return{ok:!0,port:getWebappPort(),message:`WebApp ya estaba activa en ${getWebappUrl()}`};g();const a=getWebappPort(),c=e((e,a)=>function(e,a){const c=(e.url??"/").split("?")[0],p=resolveStaticDir();if(!p)return a.writeHead(200,{"content-type":"text/html; charset=utf-8"}),void a.end(`<!doctype html><meta charset="utf-8"><title>Context Code WebApp</title><style>body{font-family:system-ui;padding:2rem;max-width:680px;margin:auto;background:#0b0b0b;color:#e6e6e6;line-height:1.5}code{background:#1a1a1a;padding:.15rem .35rem;border-radius:4px}</style><h1>Context Code WebApp</h1><p>El server WebSocket está activo en <code>ws://localhost:${getWebappPort()}/ws</code> pero el bundle estático de la PWA no está compilado todavía.</p><p>Compilá la PWA con:</p><pre><code>cd apps/webapp && pnpm install && pnpm build</code></pre><p>El build queda en <code>CLI/dist/webapp/</code> y se sirve automáticamente al refrescar.</p>`);const l=i(p,"."+("/"===c?"/index.html":c));if(!l.startsWith(p+n)&&l!==p)return a.writeHead(403),void a.end("forbidden");let d=l;if(!(t(d)&&o(d).isFile()||(d=s(p,"index.html"),t(d))))return a.writeHead(404),void a.end("not found");a.writeHead(200,{"content-type":contentTypeFor(d),"cache-control":d.endsWith("index.html")?"no-cache":"public, max-age=31536000, immutable"}),r(d).on("error",e=>{f(e);try{a.end()}catch{}}).pipe(a)}(e,a));c.on("connection",e=>{D.add(e),e.once("close",()=>{D.delete(e)})});const p=new d({noServer:!0});c.on("upgrade",(e,t,o)=>{e.url?.startsWith("/ws")?p.handleUpgrade(e,t,o,t=>p.emit("connection",t,e)):t.destroy()}),p.on("connection",(e,t)=>function(e){const t={ws:e,authed:!1,alive:!0};U.add(t),e.on("pong",()=>{t.alive=!0}),e.on("close",()=>{U.delete(t)}),e.on("error",()=>{U.delete(t)}),e.on("message",o=>{let r;try{r=JSON.parse(o.toString())}catch{return void sendError(e,"internal","Payload no es JSON válido.")}!function(e,t){if(!e.authed){if("auth"!==t.type)return void sendError(e.ws,"auth_required",'El primer mensaje debe ser de tipo "auth".');if(t.protocolVersion!==h){sendError(e.ws,"protocol_mismatch",`Versiones incompatibles: server=${h}, cliente=${t.protocolVersion}.`);try{e.ws.close(4400,"protocol mismatch")}catch{}return}const o=u().webappConfig?.token;if(!o||!v(t.token,o)){sendError(e.ws,"auth_invalid","Token inválido.");try{e.ws.close(4401,"auth invalid")}catch{}return}return e.authed=!0,e.clientId=t.clientId,void(async()=>{const t=await async function(){return B||(F||(F=(async()=>{try{const e=await import("../commands.js"),t=(await e.getCommands(process.cwd())).filter(e=>!e.isHidden).map(t=>({name:e.getCommandName(t),description:t.description??"",aliases:t.aliases?.length?[...t.aliases]:void 0,argumentHint:t.argumentHint})),o=new Set(t.map(e=>e.name.toLowerCase()));for(const e of Q)o.has(e.name.toLowerCase())||(t.push(e),o.add(e.name.toLowerCase()));return t.sort((e,t)=>e.name.localeCompare(t.name)),B=t,t}catch(e){return m(`[webapp] no pude cargar comandos: ${e instanceof Error?e.message:String(e)}`),B=[],[]}})(),F))}(),o={type:"hello",protocolVersion:h,cliVersion:b.VERSION??"0.0.0",sessionId:G,cwd:process.cwd(),backlog:[...M],availableCommands:t};try{e.ws.send(JSON.stringify(o)),await broadcastSessionsList(e.ws),broadcastProvidersList(e.ws),await broadcastModelsList(e.ws),await broadcastWorkspacesList(e.ws),await broadcastGlobalCanalStatus(e.ws)}catch(e){m(`[webapp] error enviando listas iniciales: ${e}`)}})()}switch(t.type){case"prompt":return void(t.images&&t.images.length>0?(async()=>{const e={};let o=0;for(const r of t.images){const t=Date.now()+o,a={id:t,type:"image",content:r.content,mediaType:r.mediaType,filename:r.filename||`image_${t}`},{storeImage:s}=await import("../utils/imageStore.js");await s(a),e[t]=a,o++}J.onPrompt?.(t.text,t.mode??"prompt",e)})():J.onPrompt?.(t.text,t.mode??"prompt"));case"approve_permission":return void J.onApprovePermission?.(t.id,t.forever);case"reject_permission":return void J.onRejectPermission?.(t.id,t.feedback);case"abort":return void J.onAbort?.();case"get_sessions":return void broadcastSessionsList(e.ws);case"get_providers":return void broadcastProvidersList(e.ws);case"get_models":return void broadcastModelsList(e.ws);case"get_workspaces":return void broadcastWorkspacesList(e.ws);case"get_global_canal":return void broadcastGlobalCanalStatus(e.ws);case"select_session":return T("/resume "+t.sessionId,"webapp"),void O({value:"/resume "+t.sessionId,mode:"prompt",skipSlashCommands:!1,bridgeOrigin:!1});case"select_provider":{const e="firstParty"===t.providerName?"claude":t.providerName;k(e),broadcastProvidersList(),broadcastModelsList(),T("/provider "+t.providerName,"webapp"),O({value:"/provider "+t.providerName,mode:"prompt",skipSlashCommands:!1,bridgeOrigin:!1})}return;case"select_model":{const e=W();C("firstParty"===e?"claude":e,t.modelName),broadcastModelsList(),T("/modelo "+t.modelName,"webapp"),O({value:"/modelo "+t.modelName,mode:"prompt",skipSlashCommands:!1,bridgeOrigin:!1})}return;case"select_workspace":return void(async()=>{const e=S(),o=(await _(e)).find(e=>(e.split(/[\\/]/).pop()||"Root")===t.alias);o&&(process.chdir(o),await broadcastWorkspacesList(),T("/use "+t.alias,"webapp"),O({value:"/use "+t.alias,mode:"prompt",skipSlashCommands:!1,bridgeOrigin:!1}))})();case"control_global_canal":return void(async()=>{if("start"===t.action){const e=A(),t=await I(e);if(t&&t.jid)await E(),await broadcastGlobalCanalStatus();else try{const e=await import("qrcode"),t=e.toDataURL??e.default?.toDataURL;await N({timeoutMs:12e4,onQr:async e=>{if(t){const o=await t(e);await broadcastGlobalCanalStatus(void 0,o)}else await broadcastGlobalCanalStatus(void 0,e)}}),await E(),await broadcastGlobalCanalStatus()}catch(e){m(`[webapp] Error en login QR: ${e instanceof Error?e.message:String(e)}`)}}else"stop"===t.action&&(await $(),await broadcastGlobalCanalStatus())})();case"submit_interactive_select":return void(z&&z.id===t.id&&(clearTimeout(z.timeout),z.resolve(t.value),z=null));case"submit_interactive_input":return void(q&&q.id===t.id&&(clearTimeout(q.timeout),q.resolve(t.value),q=null));case"ping":try{e.ws.send(JSON.stringify({type:"status",isLoading:!1}))}catch{}return;default:;}}(t,r)}),setTimeout(()=>{if(!t.authed)try{sendError(e,"auth_required","Cerrando conexión: timeout sin auth."),e.close(4401,"auth timeout")}catch{}},5e3)}(e));try{await new Promise((e,t)=>{c.once("error",t),c.listen(a,getWebappBindHost(),()=>e())})}catch(e){const t=e?.code,o=e instanceof Error?e.message:String(e);return"EADDRINUSE"===t?{ok:!1,port:a,message:`No pude levantar el server: el puerto ${a} sigue ocupado por otro proceso.\nProbá: /webapp port <otro> o liberá el puerto manualmente (Windows: netstat -ano | findstr :${a} → taskkill /PID <pid> /F).`}:{ok:!1,port:a,message:`No pude levantar el server en puerto ${a}: ${o}`}}return H=c,R=p,V=setInterval(heartbeatTick,3e4),m(`[webapp] server escuchando en ${getWebappUrl()}`),{ok:!0,port:a,message:`WebApp activa en ${getWebappUrl()}`}}export async function stopWebappServer(){if(!H)return{ok:!0,message:"WebApp ya estaba detenida."};try{await w()}catch(e){m(`[webapp] Error al detener el túnel: ${e instanceof Error?e.message:String(e)}`)}const e=H,t=R;H=null,R=null,V&&clearInterval(V),V=null;for(const e of U)try{e.ws.terminate()}catch{}U.clear();for(const e of D)try{e.destroy()}catch{}return D.clear(),await new Promise(e=>{if(!t)return e();let o=!1;const finish=()=>{o||(o=!0,e())};t.close(finish),setTimeout(finish,1500)}),await new Promise(t=>{let o=!1;const finish=()=>{o||(o=!0,t())};e.close(e=>{e&&m(`[webapp] close() error: ${e.message}`),finish()});const r=e;try{r.closeIdleConnections?.(),r.closeAllConnections?.()}catch(e){m(`[webapp] closeAllConnections falló: ${e instanceof Error?e.message:String(e)}`)}setTimeout(()=>{try{e.unref()}catch{}finish()},3e3)}),M.length=0,m("[webapp] server detenido y puerto liberado"),{ok:!0,message:"WebApp detenida y puerto liberado."}}export function broadcastMessage(e,t,o){if(!H)return;const r=t?.trim();if(!r)return;const a={type:"message",id:l(),role:e,text:r,ts:Date.now(),toolName:o?.toolName,quotedId:o?.quotedId};!function(e){M.push(e);for(;M.length>200;)M.shift()}(a),fanout(a)}export function broadcastPermission(e){H&&fanout({type:"permission",ts:Date.now(),...e})}export function broadcastPermissionResolved(e,t,o,r){H&&fanout({type:"permission_resolved",id:e,outcome:t,source:o,forever:r})}export function broadcastStatus(e,t,o){H&&fanout({type:"status",isLoading:e,model:t,provider:o})}export function broadcastThinking(e,t){H&&fanout({type:"thinking",text:e,isStreaming:t})}export function clearWebappBacklog(){H&&(M.length=0,fanout({type:"clear"}))}export async function broadcastSessionsList(e){if(H)try{const t=await y({dir:S(),includeWorktrees:!0}),o={type:"sessions_list",sessions:t.map(e=>({id:e.sessionId,title:e.customTitle||e.summary||"Sin título",modified:e.lastModified,messageCount:e.fileSize?Math.round(e.fileSize/150):0,firstPrompt:e.firstPrompt}))};e?e.send(JSON.stringify(o)):fanout(o)}catch(e){m(`[webapp] error en broadcastSessionsList: ${e instanceof Error?e.message:String(e)}`)}}export function broadcastProvidersList(e){if(H)try{const t=W(),o={type:"providers_list",providers:["claude","openai","openrouter","ollama","ollama-cloud","gemini-api","gemini-google","zai","minimax","nvidia","deepseek"],currentProvider:t};e?e.send(JSON.stringify(o)):fanout(o)}catch(e){m(`[webapp] error en broadcastProvidersList: ${e instanceof Error?e.message:String(e)}`)}}export async function broadcastModelsList(e){if(H)try{const t=W();let o=[];if("firstParty"===t){o=j(!1).map(e=>e.name)}else try{const e="firstParty"===t?"claude":t;o=(await P(e)).map(e=>e.name)}catch{o=[]}const r={type:"models_list",models:o,currentModel:x("firstParty"===t?"claude":t)||""};e?e.send(JSON.stringify(r)):fanout(r)}catch(e){m(`[webapp] error en broadcastModelsList: ${e instanceof Error?e.message:String(e)}`)}}export async function broadcastWorkspacesList(e){if(H)try{const t=S(),o=(await _(t)).map(e=>({alias:e.split(/[\\/]/).pop()||"Root",path:e})),r=o.find(e=>e.path===t)?.alias||"Root",a={type:"workspaces_list",workspaces:o,currentWorkspaceAlias:r};e?e.send(JSON.stringify(a)):fanout(a)}catch(e){m(`[webapp] error en broadcastWorkspacesList: ${e instanceof Error?e.message:String(e)}`)}}export async function broadcastGlobalCanalStatus(e,t){if(H)try{const o=await L(),r={type:"global_canal_status",running:o.running,pid:o.pid,startedAt:o.startedAt,whatsappOk:o.whatsappOk,telegramOk:o.telegramOk,errors:o.errors,qrCode:t};e?e.send(JSON.stringify(r)):fanout(r)}catch(e){m(`[webapp] error en broadcastGlobalCanalStatus: ${e instanceof Error?e.message:String(e)}`)}}const Q=[{name:"provider",description:"Cambiar entre proveedores de IA y configurar sus endpoints sin cerrar sesión",aliases:["proveedor","proveedores","providers"],argumentHint:"[list|current|claude|openai|openrouter|ollama|ollama-cloud|gemini-api|gemini-google|zai|minimax|nvidia]"},{name:"modelo",description:"Cambiar o ver el modelo de IA activo para el proveedor actual",aliases:["model"],argumentHint:"[nombre_modelo]"},{name:"profile",description:"Cambiar, ver o listar perfiles de IA para el proveedor de IA activo",aliases:["perfil","perfiles","profiles"],argumentHint:"[nombre_perfil]"},{name:"workspace",description:"Listar repositorios de código registrados y ver la ruta activa actual",aliases:["repos"]},{name:"use",description:"Cambiar el repositorio de código activo actual en el espacio de trabajo",aliases:["cd"],argumentHint:"<alias_del_repo>"},{name:"workspace-sync",description:"Sincronizar y registrar automáticamente repositorios de código git cercanos"},{name:"canal-global",description:"Controlar, iniciar, detener o ver el estado del Bridge Global (Daemon de WhatsApp/Telegram)",aliases:["global-canal","cg"],argumentHint:"[status|start|stop]"},{name:"aprobar",description:"Ver, aprobar o denegar permisos de ejecución de comandos pendientes enviados al chat",aliases:["approve","aprobar-siempre","approve-always","denegar","deny"],argumentHint:"[id]"},{name:"webapp",description:"Controlar el servidor del chat interactivo local en el navegador web",aliases:["aplicacion-web"],argumentHint:"[start|stop|status|open|token|port|autostart|tunnel start|tunnel stop|tunnel status|tunnel url|tunnel clear|help]"},{name:"ayuda",description:"Mostrar la ayuda interactiva de comandos del chat",aliases:["help","ayudame"]}];function fanout(e){const t=JSON.stringify(e);for(const e of U)if(e.authed)try{e.ws.send(t)}catch{}}function sendError(e,t,o){try{e.send(JSON.stringify({type:"error",code:t,message:o}))}catch{}}function heartbeatTick(){for(const e of U)if(e.alive){e.alive=!1;try{e.ws.ping()}catch{}}else{try{e.ws.terminate()}catch{}U.delete(e)}}function resolveStaticDir(){const e=c(p(import.meta.url)),o=i(e,"..","..","webapp");return t(o)&&t(s(o,"index.html"))?o:null}function contentTypeFor(e){switch(a(e).toLowerCase()){case".html":return"text/html; charset=utf-8";case".js":case".mjs":return"application/javascript; charset=utf-8";case".css":return"text/css; charset=utf-8";case".json":case".webmanifest":return"application/manifest+json; charset=utf-8";case".svg":return"image/svg+xml";case".png":return"image/png";case".ico":return"image/x-icon";case".woff2":return"font/woff2";case".woff":return"font/woff";default:return"application/octet-stream"}}
|
|
1
|
+
import{createServer as e}from"node:http";import{existsSync as t,statSync as o,createReadStream as r}from"node:fs";import{extname as a,join as s,resolve as i,sep as n}from"node:path";import{dirname as c}from"node:path";import{fileURLToPath as p}from"node:url";import{randomUUID as l}from"node:crypto";import{WebSocketServer as d}from"ws";import{getGlobalConfig as u}from"../utils/config.js";import{logForDebugging as m}from"../utils/debug.js";import{logError as f}from"../utils/log.js";import{MACRO as b}from"../recovery/bunBundleShim.js";import{ensureWebappToken as g,tokenMatches as v}from"./auth.js";import{stopTunnel as w}from"./tunnel.js";import{PROTOCOL_VERSION as h}from"./protocol.js";import{listSessionsImpl as y}from"../utils/listSessionsImpl.js";import{getOriginalCwd as S}from"../bootstrap/state.js";import{getAPIProvider as W}from"../utils/model/providers.js";import{setStoredActiveProviderPreference as k,getStoredLastModelForProvider as x,setStoredLastModelForProvider as j}from"../utils/model/providerProfilesDb.js";import{fetchProviderModels as C}from"../utils/model/providerModels.js";import{getModelOptions as P}from"../utils/model/modelOptions.js";import{getWorktreePaths as _}from"../utils/getWorktreePaths.js";import{getGlobalBridgeDaemonStatus as A,startGlobalBridgeDaemon as L,stopGlobalBridgeDaemon as E}from"../bridgeGlobal/manager.js";import{readSelfIdentity as $}from"../whatsapp/session.js";import{getWhatsAppAuthDir as I}from"../whatsapp/config.js";import{startLoginWithQr as N}from"../whatsapp/bridge.js";import{enqueue as H}from"../utils/messageQueueManager.js";import{markInjected as T}from"../mirrors/shared.js";let O=null,R=null;const U=new Set,D=new Set,M=[],G=l();let J={},V=null,z=null,q=null;export function broadcastInteractiveSelect(e,t,o,r,a){return new Promise((s,i)=>{if(!isWebappRunning()||0===U.size)return void i(new Error("WebApp no está activa o no hay clientes conectados."));z&&(clearTimeout(z.timeout),z.reject(new Error("Interrumpido por una nueva selección interactiva.")),z=null);const n=setTimeout(()=>{z&&z.id===e&&(z.reject(new Error("Timeout esperando selección del usuario en la WebApp.")),z=null)},3e5);z={id:e,resolve:s,reject:i,timeout:n},fanout({type:"interactive_select",id:e,title:t,description:r,options:o,defaultValue:a})})}export function broadcastInteractiveInput(e,t,o,r,a,s){return new Promise((i,n)=>{if(!isWebappRunning()||0===U.size)return void n(new Error("WebApp no está activa o no hay clientes conectados."));q&&(clearTimeout(q.timeout),q.reject(new Error("Interrumpido por una nueva entrada de texto interactiva.")),q=null);const c=setTimeout(()=>{q&&q.id===e&&(q.reject(new Error("Timeout esperando entrada de texto del usuario en la WebApp.")),q=null)},3e5);q={id:e,resolve:i,reject:n,timeout:c},fanout({type:"interactive_input",id:e,title:t,description:o,placeholder:r,mask:a,defaultValue:s})})}let B=null,F=null;export function setWebappHandlers(e){J={...J,...e}}export function isWebappRunning(){return null!==O}export function getWebappPort(){return u().webappConfig?.port??9876}export function getWebappBindHost(){return u().webappConfig?.bindHost??"127.0.0.1"}export function getWebappPublicUrl(){return u().webappConfig?.publicUrl??null}export function getWebappUrl(){const e=g(),t=getWebappPublicUrl();if(t){const o=t.replace(/\/+$/,""),r=o.includes("?")?"&":"?";return`${o}/${r}token=${e}`.replace(/\/\?/,"/?")}return`http://localhost:${getWebappPort()}/?token=${e}`}export function getWebappLocalUrl(){const e=g();return`http://localhost:${getWebappPort()}/?token=${e}`}export function getWebappStatus(){const e=resolveStaticDir();return{running:isWebappRunning(),port:isWebappRunning()?getWebappPort():void 0,url:isWebappRunning()?getWebappUrl():void 0,localUrl:isWebappRunning()?getWebappLocalUrl():void 0,publicUrl:getWebappPublicUrl(),bindHost:isWebappRunning()?getWebappBindHost():void 0,connections:U.size,sessionId:isWebappRunning()?G:void 0,staticDir:e,staticAvailable:Boolean(e)}}export async function startWebappServer(){if(O)return{ok:!0,port:getWebappPort(),message:`WebApp ya estaba activa en ${getWebappUrl()}`};g();const a=getWebappPort(),c=e((e,a)=>function(e,a){const c=(e.url??"/").split("?")[0],p=resolveStaticDir();if(!p)return a.writeHead(200,{"content-type":"text/html; charset=utf-8"}),void a.end(`<!doctype html><meta charset="utf-8"><title>Context Code WebApp</title><style>body{font-family:system-ui;padding:2rem;max-width:680px;margin:auto;background:#0b0b0b;color:#e6e6e6;line-height:1.5}code{background:#1a1a1a;padding:.15rem .35rem;border-radius:4px}</style><h1>Context Code WebApp</h1><p>El server WebSocket está activo en <code>ws://localhost:${getWebappPort()}/ws</code> pero el bundle estático de la PWA no está compilado todavía.</p><p>Compilá la PWA con:</p><pre><code>cd apps/webapp && pnpm install && pnpm build</code></pre><p>El build queda en <code>CLI/dist/webapp/</code> y se sirve automáticamente al refrescar.</p>`);const l=i(p,"."+("/"===c?"/index.html":c));if(!l.startsWith(p+n)&&l!==p)return a.writeHead(403),void a.end("forbidden");let d=l;if(!(t(d)&&o(d).isFile()||(d=s(p,"index.html"),t(d))))return a.writeHead(404),void a.end("not found");a.writeHead(200,{"content-type":contentTypeFor(d),"cache-control":d.endsWith("index.html")?"no-cache":"public, max-age=31536000, immutable"}),r(d).on("error",e=>{f(e);try{a.end()}catch{}}).pipe(a)}(e,a));c.on("connection",e=>{D.add(e),e.once("close",()=>{D.delete(e)})});const p=new d({noServer:!0});c.on("upgrade",(e,t,o)=>{e.url?.startsWith("/ws")?p.handleUpgrade(e,t,o,t=>p.emit("connection",t,e)):t.destroy()}),p.on("connection",(e,t)=>function(e){const t={ws:e,authed:!1,alive:!0};U.add(t),e.on("pong",()=>{t.alive=!0}),e.on("close",()=>{U.delete(t)}),e.on("error",()=>{U.delete(t)}),e.on("message",o=>{let r;try{r=JSON.parse(o.toString())}catch{return void sendError(e,"internal","Payload no es JSON válido.")}!function(e,t){if(!e.authed){if("auth"!==t.type)return void sendError(e.ws,"auth_required",'El primer mensaje debe ser de tipo "auth".');if(t.protocolVersion!==h){sendError(e.ws,"protocol_mismatch",`Versiones incompatibles: server=${h}, cliente=${t.protocolVersion}.`);try{e.ws.close(4400,"protocol mismatch")}catch{}return}const o=u().webappConfig?.token;if(!o||!v(t.token,o)){sendError(e.ws,"auth_invalid","Token inválido.");try{e.ws.close(4401,"auth invalid")}catch{}return}return e.authed=!0,e.clientId=t.clientId,void(async()=>{const t=await async function(){return B||(F||(F=(async()=>{try{const e=await import("../commands.js"),t=(await e.getCommands(process.cwd())).filter(e=>!e.isHidden).map(t=>({name:e.getCommandName(t),description:t.description??"",aliases:t.aliases?.length?[...t.aliases]:void 0,argumentHint:t.argumentHint})),o=new Set(t.map(e=>e.name.toLowerCase()));for(const e of Q)o.has(e.name.toLowerCase())||(t.push(e),o.add(e.name.toLowerCase()));return t.sort((e,t)=>e.name.localeCompare(t.name)),B=t,t}catch(e){return m(`[webapp] no pude cargar comandos: ${e instanceof Error?e.message:String(e)}`),B=[],[]}})(),F))}(),o={type:"hello",protocolVersion:h,cliVersion:b.VERSION??"0.0.0",sessionId:G,cwd:process.cwd(),backlog:[...M],availableCommands:t};try{e.ws.send(JSON.stringify(o)),await broadcastSessionsList(e.ws),broadcastProvidersList(e.ws),await broadcastModelsList(e.ws),await broadcastWorkspacesList(e.ws),await broadcastGlobalCanalStatus(e.ws)}catch(e){m(`[webapp] error enviando listas iniciales: ${e}`)}})()}switch(t.type){case"prompt":return void(async()=>{const{getActiveHeadlessServer:e}=await import("../server/channelServer.js"),o=e();if(o)await o.handleSubmitPromptDirect(t.text);else if(t.images&&t.images.length>0){const e={};let o=0;for(const r of t.images){const t=Date.now()+o,a={id:t,type:"image",content:r.content,mediaType:r.mediaType,filename:r.filename||`image_${t}`},{storeImage:s}=await import("../utils/imageStore.js");await s(a),e[t]=a,o++}J.onPrompt?.(t.text,t.mode??"prompt",e)}else J.onPrompt?.(t.text,t.mode??"prompt")})();case"approve_permission":return void(async()=>{const{getActiveHeadlessServer:e}=await import("../server/channelServer.js"),o=e();o?o.handleApproveTool({tool_use_id:t.id}):J.onApprovePermission?.(t.id,t.forever)})();case"reject_permission":return void(async()=>{const{getActiveHeadlessServer:e}=await import("../server/channelServer.js"),o=e();o?o.handleRejectTool({tool_use_id:t.id}):J.onRejectPermission?.(t.id,t.feedback)})();case"abort":return void(async()=>{const{getActiveHeadlessServer:e}=await import("../server/channelServer.js"),t=e();t?t.handleAbort():J.onAbort?.()})();case"get_sessions":return void broadcastSessionsList(e.ws);case"get_providers":return void broadcastProvidersList(e.ws);case"get_models":return void broadcastModelsList(e.ws);case"get_workspaces":return void broadcastWorkspacesList(e.ws);case"get_global_canal":return void broadcastGlobalCanalStatus(e.ws);case"select_session":return T("/resume "+t.sessionId,"webapp"),void H({value:"/resume "+t.sessionId,mode:"prompt",skipSlashCommands:!1,bridgeOrigin:!1});case"select_provider":{const e="firstParty"===t.providerName?"claude":t.providerName;k(e),broadcastProvidersList(),broadcastModelsList(),T("/provider "+t.providerName,"webapp"),H({value:"/provider "+t.providerName,mode:"prompt",skipSlashCommands:!1,bridgeOrigin:!1})}return;case"select_model":{const e=W();j("firstParty"===e?"claude":e,t.modelName),broadcastModelsList(),T("/modelo "+t.modelName,"webapp"),H({value:"/modelo "+t.modelName,mode:"prompt",skipSlashCommands:!1,bridgeOrigin:!1})}return;case"select_workspace":return void(async()=>{const e=S(),o=(await _(e)).find(e=>(e.split(/[\\/]/).pop()||"Root")===t.alias);o&&(process.chdir(o),await broadcastWorkspacesList(),T("/use "+t.alias,"webapp"),H({value:"/use "+t.alias,mode:"prompt",skipSlashCommands:!1,bridgeOrigin:!1}))})();case"control_global_canal":return void(async()=>{if("start"===t.action){const e=I(),t=await $(e);if(t&&t.jid)await L(),await broadcastGlobalCanalStatus();else try{const e=await import("qrcode"),t=e.toDataURL??e.default?.toDataURL;await N({timeoutMs:12e4,onQr:async e=>{if(t){const o=await t(e);await broadcastGlobalCanalStatus(void 0,o)}else await broadcastGlobalCanalStatus(void 0,e)}}),await L(),await broadcastGlobalCanalStatus()}catch(e){m(`[webapp] Error en login QR: ${e instanceof Error?e.message:String(e)}`)}}else"stop"===t.action&&(await E(),await broadcastGlobalCanalStatus())})();case"submit_interactive_select":return void(z&&z.id===t.id&&(clearTimeout(z.timeout),z.resolve(t.value),z=null));case"submit_interactive_input":return void(q&&q.id===t.id&&(clearTimeout(q.timeout),q.resolve(t.value),q=null));case"ping":try{e.ws.send(JSON.stringify({type:"status",isLoading:!1}))}catch{}return;default:;}}(t,r)}),setTimeout(()=>{if(!t.authed)try{sendError(e,"auth_required","Cerrando conexión: timeout sin auth."),e.close(4401,"auth timeout")}catch{}},5e3)}(e));try{await new Promise((e,t)=>{c.once("error",t),c.listen(a,getWebappBindHost(),()=>e())})}catch(e){const t=e?.code,o=e instanceof Error?e.message:String(e);return"EADDRINUSE"===t?{ok:!1,port:a,message:`No pude levantar el server: el puerto ${a} sigue ocupado por otro proceso.\nProbá: /webapp port <otro> o liberá el puerto manualmente (Windows: netstat -ano | findstr :${a} → taskkill /PID <pid> /F).`}:{ok:!1,port:a,message:`No pude levantar el server en puerto ${a}: ${o}`}}return O=c,R=p,V=setInterval(heartbeatTick,3e4),m(`[webapp] server escuchando en ${getWebappUrl()}`),{ok:!0,port:a,message:`WebApp activa en ${getWebappUrl()}`}}export async function stopWebappServer(){if(!O)return{ok:!0,message:"WebApp ya estaba detenida."};try{await w()}catch(e){m(`[webapp] Error al detener el túnel: ${e instanceof Error?e.message:String(e)}`)}const e=O,t=R;O=null,R=null,V&&clearInterval(V),V=null;for(const e of U)try{e.ws.terminate()}catch{}U.clear();for(const e of D)try{e.destroy()}catch{}return D.clear(),await new Promise(e=>{if(!t)return e();let o=!1;const finish=()=>{o||(o=!0,e())};t.close(finish),setTimeout(finish,1500)}),await new Promise(t=>{let o=!1;const finish=()=>{o||(o=!0,t())};e.close(e=>{e&&m(`[webapp] close() error: ${e.message}`),finish()});const r=e;try{r.closeIdleConnections?.(),r.closeAllConnections?.()}catch(e){m(`[webapp] closeAllConnections falló: ${e instanceof Error?e.message:String(e)}`)}setTimeout(()=>{try{e.unref()}catch{}finish()},3e3)}),M.length=0,m("[webapp] server detenido y puerto liberado"),{ok:!0,message:"WebApp detenida y puerto liberado."}}export function broadcastMessage(e,t,o){if(!O)return;const r=t?.trim();if(!r)return;const a={type:"message",id:l(),role:e,text:r,ts:Date.now(),toolName:o?.toolName,quotedId:o?.quotedId};!function(e){M.push(e);for(;M.length>200;)M.shift()}(a),fanout(a)}export function broadcastPermission(e){O&&fanout({type:"permission",ts:Date.now(),...e})}export function broadcastPermissionResolved(e,t,o,r){O&&fanout({type:"permission_resolved",id:e,outcome:t,source:o,forever:r})}export function broadcastStatus(e,t,o){O&&fanout({type:"status",isLoading:e,model:t,provider:o})}export function broadcastThinking(e,t){O&&fanout({type:"thinking",text:e,isStreaming:t})}export function clearWebappBacklog(){O&&(M.length=0,fanout({type:"clear"}))}export async function broadcastSessionsList(e){if(O)try{const t=await y({dir:S(),includeWorktrees:!0}),o={type:"sessions_list",sessions:t.map(e=>({id:e.sessionId,title:e.customTitle||e.summary||"Sin título",modified:e.lastModified,messageCount:e.fileSize?Math.round(e.fileSize/150):0,firstPrompt:e.firstPrompt}))};e?e.send(JSON.stringify(o)):fanout(o)}catch(e){m(`[webapp] error en broadcastSessionsList: ${e instanceof Error?e.message:String(e)}`)}}export function broadcastProvidersList(e){if(O)try{const t=W(),o={type:"providers_list",providers:["claude","openai","openrouter","ollama","ollama-cloud","gemini-api","gemini-google","zai","minimax","nvidia","deepseek"],currentProvider:t};e?e.send(JSON.stringify(o)):fanout(o)}catch(e){m(`[webapp] error en broadcastProvidersList: ${e instanceof Error?e.message:String(e)}`)}}export async function broadcastModelsList(e){if(O)try{const t=W();let o=[];if("firstParty"===t){o=P(!1).map(e=>e.name)}else try{const e="firstParty"===t?"claude":t;o=(await C(e)).map(e=>e.name)}catch{o=[]}const r={type:"models_list",models:o,currentModel:x("firstParty"===t?"claude":t)||""};e?e.send(JSON.stringify(r)):fanout(r)}catch(e){m(`[webapp] error en broadcastModelsList: ${e instanceof Error?e.message:String(e)}`)}}export async function broadcastWorkspacesList(e){if(O)try{const t=S(),o=(await _(t)).map(e=>({alias:e.split(/[\\/]/).pop()||"Root",path:e})),r=o.find(e=>e.path===t)?.alias||"Root",a={type:"workspaces_list",workspaces:o,currentWorkspaceAlias:r};e?e.send(JSON.stringify(a)):fanout(a)}catch(e){m(`[webapp] error en broadcastWorkspacesList: ${e instanceof Error?e.message:String(e)}`)}}export async function broadcastGlobalCanalStatus(e,t){if(O)try{const o=await A(),r={type:"global_canal_status",running:o.running,pid:o.pid,startedAt:o.startedAt,whatsappOk:o.whatsappOk,telegramOk:o.telegramOk,errors:o.errors,qrCode:t};e?e.send(JSON.stringify(r)):fanout(r)}catch(e){m(`[webapp] error en broadcastGlobalCanalStatus: ${e instanceof Error?e.message:String(e)}`)}}const Q=[{name:"provider",description:"Cambiar entre proveedores de IA y configurar sus endpoints sin cerrar sesión",aliases:["proveedor","proveedores","providers"],argumentHint:"[list|current|claude|openai|openrouter|ollama|ollama-cloud|gemini-api|gemini-google|zai|minimax|nvidia]"},{name:"modelo",description:"Cambiar o ver el modelo de IA activo para el proveedor actual",aliases:["model"],argumentHint:"[nombre_modelo]"},{name:"profile",description:"Cambiar, ver o listar perfiles de IA para el proveedor de IA activo",aliases:["perfil","perfiles","profiles"],argumentHint:"[nombre_perfil]"},{name:"workspace",description:"Listar repositorios de código registrados y ver la ruta activa actual",aliases:["repos"]},{name:"use",description:"Cambiar el repositorio de código activo actual en el espacio de trabajo",aliases:["cd"],argumentHint:"<alias_del_repo>"},{name:"workspace-sync",description:"Sincronizar y registrar automáticamente repositorios de código git cercanos"},{name:"canal-global",description:"Controlar, iniciar, detener o ver el estado del Bridge Global (Daemon de WhatsApp/Telegram)",aliases:["global-canal","cg"],argumentHint:"[status|start|stop]"},{name:"aprobar",description:"Ver, aprobar o denegar permisos de ejecución de comandos pendientes enviados al chat",aliases:["approve","aprobar-siempre","approve-always","denegar","deny"],argumentHint:"[id]"},{name:"webapp",description:"Controlar el servidor del chat interactivo local en el navegador web",aliases:["aplicacion-web"],argumentHint:"[start|stop|status|open|token|port|autostart|tunnel start|tunnel stop|tunnel status|tunnel url|tunnel clear|help]"},{name:"ayuda",description:"Mostrar la ayuda interactiva de comandos del chat",aliases:["help","ayudame"]}];function fanout(e){const t=JSON.stringify(e);for(const e of U)if(e.authed)try{e.ws.send(t)}catch{}}function sendError(e,t,o){try{e.send(JSON.stringify({type:"error",code:t,message:o}))}catch{}}function heartbeatTick(){for(const e of U)if(e.alive){e.alive=!1;try{e.ws.ping()}catch{}}else{try{e.ws.terminate()}catch{}U.delete(e)}}function resolveStaticDir(){const e=c(p(import.meta.url)),o=i(e,"..","..","webapp");return t(o)&&t(s(o,"index.html"))?o:null}function contentTypeFor(e){switch(a(e).toLowerCase()){case".html":return"text/html; charset=utf-8";case".js":case".mjs":return"application/javascript; charset=utf-8";case".css":return"text/css; charset=utf-8";case".json":case".webmanifest":return"application/manifest+json; charset=utf-8";case".svg":return"image/svg+xml";case".png":return"image/png";case".ico":return"image/x-icon";case".woff2":return"font/woff2";case".woff":return"font/woff";default:return"application/octet-stream"}}
|
package/dist/webapp/ngsw.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@iaforged/context-code",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.3",
|
|
4
4
|
"description": "Context Code es un asistente de desarrollo para la terminal. Puede revisar tu proyecto, editar archivos, ejecutar comandos y apoyarte en tareas reales de programacion.",
|
|
5
5
|
"author": "Context AI",
|
|
6
6
|
"license": "MIT",
|