everclaw 0.3.4 → 0.3.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/index.js +30 -28
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -76,7 +76,7 @@ var li=Object.defineProperty;var ci=(o=>typeof require<"u"?require:typeof Proxy<
76
76
  name TEXT NOT NULL,
77
77
  applied_at TEXT NOT NULL
78
78
  );
79
- `)}function Le(o={}){let e=o.dbPath??hi(o.dataDir);Ve(Ro.dirname(e));let t=fi(),n=new t(e);n.exec("PRAGMA journal_mode = WAL;"),n.exec("PRAGMA foreign_keys = ON;"),n.exec("PRAGMA busy_timeout = 5000;"),yi(n);let r=To.at(-1)?.version??0,s=n.prepare("SELECT COALESCE(MAX(version), 0) AS version FROM schema_migrations").get().version;if(s>r)throw n.close(),new Error(`Operational storage schema version ${s} is newer than supported version ${r}.`);let i=new Set(n.prepare("SELECT version FROM schema_migrations ORDER BY version").all().map(a=>a.version));for(let a of To)i.has(a.version)||Ao(n,()=>{n.exec(a.sql),n.prepare("INSERT INTO schema_migrations (version, name, applied_at) VALUES (?, ?, ?)").run(a.version,a.name,ie())});return new Lr(n,e)}var bi=new Set(["agent","gateway"]);function vi(o){for(let e of o.slice(2))if(!e.startsWith("-"))return e;return null}function wi(o){let e=vi(o);return!!e&&bi.has(e)}function Eo(o,e={}){if(!wi(o))return!1;let t=e.openStorage??Le,n=e.onError??(s=>console.error(s)),r=e.exit??(s=>process.exit(s));try{return t().close(),!0}catch(s){let i=s instanceof Error?s.message:String(s);return n(`Failed to initialize operational storage: ${i}`),r(1),!1}}Ne();Tt();import ge from"node:fs";import ti from"node:readline/promises";import{stdin as ni,stdout as ri}from"node:process";import{Command as Tc,Option as yo}from"commander";import Fe from"prompts";import S from"chalk";function Ci(o){let e={};if(o.EVERCLAW_PROVIDER&&(e.provider=o.EVERCLAW_PROVIDER),o.EVERCLAW_MODEL&&(e.model=o.EVERCLAW_MODEL),o.EVERCLAW_API_KEY&&(e.apiKey=o.EVERCLAW_API_KEY),o.EVERCLAW_API_BASE&&(e.apiBase=o.EVERCLAW_API_BASE),o.EVERCLAW_GATEWAY_HOST&&(e.gatewayHost=o.EVERCLAW_GATEWAY_HOST),o.EVERCLAW_GATEWAY_PORT){let t=Number(o.EVERCLAW_GATEWAY_PORT);Number.isNaN(t)||(e.gatewayPort=t)}if(o.EVERCLAW_DASHBOARD!==void 0){let t=o.EVERCLAW_DASHBOARD.toLowerCase();(t==="true"||t==="false")&&(e.dashboardEnabled=t==="true")}return e}function Lo(o,e){let t=structuredClone(o);if(e.provider!==void 0&&(t.agents.defaults.provider=e.provider),e.model!==void 0&&(t.agents.defaults.model=e.model),e.gatewayHost!==void 0&&(t.gateway.host=e.gatewayHost),e.gatewayPort!==void 0&&(t.gateway.port=e.gatewayPort),e.dashboardEnabled!==void 0){let n=t.gateway;n.dashboard&&typeof n.dashboard=="object"&&(n.dashboard.enabled=e.dashboardEnabled)}if(e.apiKey!==void 0||e.apiBase!==void 0){let n=t.agents.defaults.provider;n&&n!=="auto"&&(t.providers[n]||(t.providers[n]={apiKey:"",apiBase:null,extraHeaders:null}),e.apiKey!==void 0&&(t.providers[n].apiKey=e.apiKey),e.apiBase!==void 0&&(t.providers[n].apiBase=e.apiBase))}return t}function Kt(o,e,t){let n=Ci(e),r=Lo(o,n);return t?Lo(r,t):r}le();le();import At from"node:fs";import Do from"node:path";import Ti from"node:os";var Ri="gateway.pid";function jr(){return Do.join(Ti.homedir(),it,Ri)}function Fr(o){let e=jr();At.mkdirSync(Do.dirname(e),{recursive:!0}),At.writeFileSync(e,JSON.stringify(o,null,2),"utf8")}function Ee(){let o=jr();if(!At.existsSync(o))return null;try{let e=At.readFileSync(o,"utf8");return JSON.parse(e)}catch{return null}}function Pe(o){let e=jr();try{if(!At.existsSync(e))return;if(o!==void 0){let t=Ee();if(t&&t.pid!==o)return}At.unlinkSync(e)}catch{}}function Ae(o){try{return process.kill(o,0),!0}catch{return!1}}async function Br(o,e){let t=Date.now();for(;Date.now()-t<e;){if(!Ae(o))return!0;await new Promise(n=>setTimeout(n,200))}return!Ae(o)}function dt(o){let e=new Date(o).getTime();if(Number.isNaN(e))return"unknown";let t=Date.now()-e;if(t<0)return"unknown";let n=Math.floor(t/1e3),r=Math.floor(n/86400),s=Math.floor(n%86400/3600),i=Math.floor(n%3600/60),a=[];return r>0&&a.push(`${r}d`),s>0&&a.push(`${s}h`),a.push(`${i}m`),a.join(" ")}$e();var Jt=class{items=[];waiters=[];push(e){let t=this.waiters.shift();t?t(e):this.items.push(e)}async pop(){let e=this.items.shift();return e!==void 0?e:new Promise(t=>this.waiters.push(t))}size(){return this.items.length}};var ut=class{inbound=new Jt;outbound=new Jt;async publishInbound(e){this.inbound.push(e)}async consumeInbound(){return this.inbound.pop()}async publishOutbound(e){this.outbound.push(e)}async consumeOutbound(){return this.outbound.pop()}get inboundSize(){return this.inbound.size()}get outboundSize(){return this.outbound.size()}};import cs from"node:path";import No from"node:fs";import An from"node:path";import jo from"node:os";import qt from"node:fs";import Tn from"node:path";var Ai=[{type:"function",function:{name:"save_memory",description:"Save the memory consolidation result to persistent storage.",parameters:{type:"object",properties:{history_entry:{type:"string"},memory_update:{type:"string"}},required:["history_entry","memory_update"]}}}],Ht=class{memoryDir;memoryFile;historyFile;constructor(e,t){let n=Tn.join(e,"memory");this.memoryDir=t?Tn.join(n,t):n,qt.mkdirSync(this.memoryDir,{recursive:!0}),this.memoryFile=Tn.join(this.memoryDir,"MEMORY.md"),this.historyFile=Tn.join(this.memoryDir,"HISTORY.md")}readLongTerm(){return qt.existsSync(this.memoryFile)?qt.readFileSync(this.memoryFile,"utf8"):""}writeLongTerm(e){qt.writeFileSync(this.memoryFile,e,"utf8")}appendHistory(e){qt.appendFileSync(this.historyFile,`${e.trim()}
79
+ `)}function Le(o={}){let e=o.dbPath??hi(o.dataDir);Ve(Ro.dirname(e));let t=fi(),n=new t(e);n.exec("PRAGMA journal_mode = WAL;"),n.exec("PRAGMA foreign_keys = ON;"),n.exec("PRAGMA busy_timeout = 5000;"),yi(n);let r=To.at(-1)?.version??0,s=n.prepare("SELECT COALESCE(MAX(version), 0) AS version FROM schema_migrations").get().version;if(s>r)throw n.close(),new Error(`Operational storage schema version ${s} is newer than supported version ${r}.`);let i=new Set(n.prepare("SELECT version FROM schema_migrations ORDER BY version").all().map(a=>a.version));for(let a of To)i.has(a.version)||Ao(n,()=>{n.exec(a.sql),n.prepare("INSERT INTO schema_migrations (version, name, applied_at) VALUES (?, ?, ?)").run(a.version,a.name,ie())});return new Lr(n,e)}var bi=new Set(["agent","gateway"]);function vi(o){for(let e of o.slice(2))if(!e.startsWith("-"))return e;return null}function wi(o){let e=vi(o);return!!e&&bi.has(e)}function Eo(o,e={}){if(!wi(o))return!1;let t=e.openStorage??Le,n=e.onError??(s=>console.error(s)),r=e.exit??(s=>process.exit(s));try{return t().close(),!0}catch(s){let i=s instanceof Error?s.message:String(s);return n(`Failed to initialize operational storage: ${i}`),r(1),!1}}Ne();Tt();import ge from"node:fs";import ti from"node:readline/promises";import{stdin as ni,stdout as ri}from"node:process";import{Command as Ec,Option as yo}from"commander";import Fe from"prompts";import S from"chalk";function Ci(o){let e={};if(o.EVERCLAW_PROVIDER&&(e.provider=o.EVERCLAW_PROVIDER),o.EVERCLAW_MODEL&&(e.model=o.EVERCLAW_MODEL),o.EVERCLAW_API_KEY&&(e.apiKey=o.EVERCLAW_API_KEY),o.EVERCLAW_API_BASE&&(e.apiBase=o.EVERCLAW_API_BASE),o.EVERCLAW_GATEWAY_HOST&&(e.gatewayHost=o.EVERCLAW_GATEWAY_HOST),o.EVERCLAW_GATEWAY_PORT){let t=Number(o.EVERCLAW_GATEWAY_PORT);Number.isNaN(t)||(e.gatewayPort=t)}if(o.EVERCLAW_DASHBOARD!==void 0){let t=o.EVERCLAW_DASHBOARD.toLowerCase();(t==="true"||t==="false")&&(e.dashboardEnabled=t==="true")}return e}function Lo(o,e){let t=structuredClone(o);if(e.provider!==void 0&&(t.agents.defaults.provider=e.provider),e.model!==void 0&&(t.agents.defaults.model=e.model),e.gatewayHost!==void 0&&(t.gateway.host=e.gatewayHost),e.gatewayPort!==void 0&&(t.gateway.port=e.gatewayPort),e.dashboardEnabled!==void 0){let n=t.gateway;n.dashboard&&typeof n.dashboard=="object"&&(n.dashboard.enabled=e.dashboardEnabled)}if(e.apiKey!==void 0||e.apiBase!==void 0){let n=t.agents.defaults.provider;n&&n!=="auto"&&(t.providers[n]||(t.providers[n]={apiKey:"",apiBase:null,extraHeaders:null}),e.apiKey!==void 0&&(t.providers[n].apiKey=e.apiKey),e.apiBase!==void 0&&(t.providers[n].apiBase=e.apiBase))}return t}function Kt(o,e,t){let n=Ci(e),r=Lo(o,n);return t?Lo(r,t):r}le();le();import At from"node:fs";import Do from"node:path";import Ti from"node:os";var Ri="gateway.pid";function jr(){return Do.join(Ti.homedir(),it,Ri)}function Fr(o){let e=jr();At.mkdirSync(Do.dirname(e),{recursive:!0}),At.writeFileSync(e,JSON.stringify(o,null,2),"utf8")}function Ee(){let o=jr();if(!At.existsSync(o))return null;try{let e=At.readFileSync(o,"utf8");return JSON.parse(e)}catch{return null}}function Pe(o){let e=jr();try{if(!At.existsSync(e))return;if(o!==void 0){let t=Ee();if(t&&t.pid!==o)return}At.unlinkSync(e)}catch{}}function Ae(o){try{return process.kill(o,0),!0}catch{return!1}}async function Br(o,e){let t=Date.now();for(;Date.now()-t<e;){if(!Ae(o))return!0;await new Promise(n=>setTimeout(n,200))}return!Ae(o)}function dt(o){let e=new Date(o).getTime();if(Number.isNaN(e))return"unknown";let t=Date.now()-e;if(t<0)return"unknown";let n=Math.floor(t/1e3),r=Math.floor(n/86400),s=Math.floor(n%86400/3600),i=Math.floor(n%3600/60),a=[];return r>0&&a.push(`${r}d`),s>0&&a.push(`${s}h`),a.push(`${i}m`),a.join(" ")}$e();var Jt=class{items=[];waiters=[];push(e){let t=this.waiters.shift();t?t(e):this.items.push(e)}async pop(){let e=this.items.shift();return e!==void 0?e:new Promise(t=>this.waiters.push(t))}size(){return this.items.length}};var ut=class{inbound=new Jt;outbound=new Jt;async publishInbound(e){this.inbound.push(e)}async consumeInbound(){return this.inbound.pop()}async publishOutbound(e){this.outbound.push(e)}async consumeOutbound(){return this.outbound.pop()}get inboundSize(){return this.inbound.size()}get outboundSize(){return this.outbound.size()}};import cs from"node:path";import No from"node:fs";import An from"node:path";import jo from"node:os";import qt from"node:fs";import Tn from"node:path";var Ai=[{type:"function",function:{name:"save_memory",description:"Save the memory consolidation result to persistent storage.",parameters:{type:"object",properties:{history_entry:{type:"string"},memory_update:{type:"string"}},required:["history_entry","memory_update"]}}}],Ht=class{memoryDir;memoryFile;historyFile;constructor(e,t){let n=Tn.join(e,"memory");this.memoryDir=t?Tn.join(n,t):n,qt.mkdirSync(this.memoryDir,{recursive:!0}),this.memoryFile=Tn.join(this.memoryDir,"MEMORY.md"),this.historyFile=Tn.join(this.memoryDir,"HISTORY.md")}readLongTerm(){return qt.existsSync(this.memoryFile)?qt.readFileSync(this.memoryFile,"utf8"):""}writeLongTerm(e){qt.writeFileSync(this.memoryFile,e,"utf8")}appendHistory(e){qt.appendFileSync(this.historyFile,`${e.trim()}
80
80
 
81
81
  `,"utf8")}getMemoryContext(){let e=this.readLongTerm();return e?`## Long-term Memory
82
82
  ${e}`:""}async consolidate(e,t,n,r){let s=r?.archiveAll??!1,i=r?.memoryWindow??50,a=[],l=0;if(s)a=e.messages,l=0;else if(l=Math.floor(i/2),e.messages.length<=l||e.messages.length-e.lastConsolidated<=0||(a=e.messages.slice(e.lastConsolidated,e.messages.length-l),!a.length))return!0;let c=[],u=[];for(let v of a)v._type==="anchor"?c.push(v):u.push(v);let g=[];for(let v of c)g.push(`[ANCHOR] ${v.name}: ${v.summary??"(no summary)"}`);for(let v of u){if(!v.content&&!v._full_content)continue;let d=Array.isArray(v.tools_used)&&v.tools_used.length?` [tools: ${v.tools_used.join(", ")}]`:"",b=v._full_content??v.content;g.push(`[${String(v.timestamp??"?").slice(0,16)}] ${String(v.role).toUpperCase()}${d}: ${String(b)}`)}let h=this.readLongTerm(),T=`Process this conversation and call the save_memory tool with your consolidation.
@@ -263,11 +263,11 @@ Summarize this naturally for the user. Keep it brief (1-2 sentences).`,i={channe
263
263
 
264
264
  `)}]});let s=(e.tools??[]).map(i=>i).filter(i=>i.type==="function"&&i.function?.name).map(i=>({name:i.function.name,description:i.function?.description??"",parameters:i.function?.parameters??{type:"object",properties:{}}}));return s.length&&(r.tools=[{functionDeclarations:s}],r.toolConfig={functionCallingConfig:{mode:"AUTO"}}),e.imageOutput&&(r.responseModalities=["TEXT","IMAGE"]),r}async chat(e){try{Y(e.signal);let t=this.resolveModel(e.model??this.defaultModel),r=`${(this.apiBase??o.DEFAULT_BASE).replace(/\/$/,"")}/models/${encodeURIComponent(t)}:generateContent`,s=this.toGemini(e),i=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json","x-goog-api-key":this.apiKey},body:JSON.stringify(s),...e.signal?{signal:e.signal}:{}}),a=await i.json();if(!i.ok)return{content:`Error calling LLM: ${a?.error?.message??JSON.stringify(a)}`,toolCalls:[],finishReason:"error",usage:{},reasoningContent:null};let l=a?.candidates?.[0],c=l?.content?.parts??[],u=c.filter(v=>typeof v?.text=="string").map(v=>String(v.text)),g=c.filter(v=>v?.functionCall?.name).map(v=>({id:_a(9),name:String(v.functionCall.name),arguments:this.parseToolArgs(v.functionCall.args)})),h={};a?.usageMetadata&&(h.prompt_tokens=Number(a.usageMetadata.promptTokenCount??0),h.completion_tokens=Number(a.usageMetadata.candidatesTokenCount??0),h.total_tokens=Number(a.usageMetadata.totalTokenCount??0));let T=String(l?.finishReason??"STOP").toLowerCase();return{content:u.length?u.join(`
265
265
  `):null,toolCalls:g,finishReason:T,usage:h,reasoningContent:null}}catch(t){if(te(t))throw t;return{content:`Error calling LLM: ${String(t)}`,toolCalls:[],finishReason:"error",usage:{},reasoningContent:null}}}};import{nanoid as Oa}from"nanoid";le();var ur=class o{constructor(e,t,n,r){this.apiKey=e;this.apiBase=t;this.defaultModel=n;this.providerName=r}static DEFAULT_BASE_BY_PROVIDER={openrouter:"https://openrouter.ai/api/v1",openai:"https://api.openai.com/v1",deepseek:"https://api.deepseek.com/v1",groq:"https://api.groq.com/openai/v1",moonshot:"https://api.moonshot.ai/v1",minimax:"https://api.minimax.io/v1",dashscope:"https://dashscope.aliyuncs.com/compatible-mode/v1",zhipu:"https://open.bigmodel.cn/api/paas/v4",siliconflow:"https://api.siliconflow.cn/v1",volcengine:"https://ark.cn-beijing.volces.com/api/v3",vllm:"http://localhost:8000/v1",ollama:"http://localhost:11434/v1",zai:"https://api.z.ai/api/coding/paas/v4"};static UNSUPPORTED_PROVIDERS=new Set(["anthropic","gemini","openai_codex","github_copilot"]);getDefaultModel(){return this.defaultModel}resolveModel(e){let t=n=>n.toLowerCase().replace(/-/g,"_");if(e.includes("/")){let n=e.split("/",2),r=n[0],s=n[1];if(!r||!s)return e;if(t(r)==="github_copilot")return`github_copilot/${s}`;if(t(r)==="openai_codex")return`openai_codex/${s}`;if(t(r)==="groq")return s==="compound"||s==="compound-mini"?`groq/${s}`:s;if(t(r)==="ollama")return s}return e}async chat(e){let n={model:this.resolveModel(e.model??this.defaultModel),messages:rn(e.messages),max_tokens:Math.max(1,e.maxTokens??4096),temperature:e.temperature??.7};e.tools?.length&&(n.tools=e.tools,n.tool_choice="auto"),e.reasoning&&(n.reasoning_effort="medium"),e.imageOutput&&(n.include_image_output=!0);try{Y(e.signal);let r=(this.providerName??"").trim();if(r&&o.UNSUPPORTED_PROVIDERS.has(r))return{content:`Error calling LLM: provider '${r}' is not supported in this TypeScript port yet. Use openrouter/openai/deepseek/groq/custom.`,toolCalls:[],finishReason:"error",usage:{},reasoningContent:null};let s=this.apiBase??(r?o.DEFAULT_BASE_BY_PROVIDER[r]:void 0)??(this.apiKey?.startsWith("sk-or-")?o.DEFAULT_BASE_BY_PROVIDER.openrouter:void 0);if(!s)return{content:`Error calling LLM: api_base not configured. Set provider/api_base in ${at} or run everclaw onboard.`,toolCalls:[],finishReason:"error",usage:{},reasoningContent:null};let i={"Content-Type":"application/json"};this.apiKey&&(i.Authorization=`Bearer ${this.apiKey}`);let a=await fetch(`${s.replace(/\/$/,"")}/chat/completions`,{method:"POST",headers:i,body:JSON.stringify(n),...e.signal?{signal:e.signal}:{}}),l=await a.json();if(!a.ok){let g=l?.error?.code??"",h=l?.error?.message??JSON.stringify(l);return g==="model_not_found"?{content:`Error calling LLM: ${h}
266
- ${r==="groq"?"Try a Groq-supported model like llama-3.3-70b-versatile or openai/gpt-oss-120b. You can run `everclaw doctor`.":"Check your model id and provider access. You can run `everclaw doctor`."}`,toolCalls:[],finishReason:"error",usage:{},reasoningContent:null}:{content:`Error calling LLM: ${h}`,toolCalls:[],finishReason:"error",usage:{},reasoningContent:null}}let c=l.choices?.[0]?.message?l.choices[0]:null;if(!c)return{content:`Error calling LLM: ${JSON.stringify(l)}`,toolCalls:[],finishReason:"error",usage:{},reasoningContent:null};let u=(c.message.tool_calls??[]).map(g=>({id:Oa(9),name:g.function.name,arguments:typeof g.function.arguments=="string"?JSON.parse(g.function.arguments||"{}"):g.function.arguments}));return{content:c.message.content??null,toolCalls:u,finishReason:c.finish_reason??"stop",usage:l.usage??{},reasoningContent:c.message.reasoning_content??null}}catch(r){if(te(r))throw r;return{content:`Error calling LLM: ${String(r)}`,toolCalls:[],finishReason:"error",usage:{},reasoningContent:null}}}};function _e(o){let e=o.agents.defaults.model,t=Xe(o,e),n=_o(o,e),r=t&&ct(t)?Ct(o,t,e):null,s=new Set(["openai_codex","github_copilot"]),i=new Set(["anthropic"]);if(!t)throw new Error("No provider could be resolved from config. Run `everclaw onboard` and set provider/model/API key.");if(ct(t)&&!r)throw new Error(`Custom provider '${t}' could not be found. Check ${at}.`);if(i.has(t))throw new Error(`Provider '${t}' is not supported in this TypeScript port yet. Use openrouter/openai/deepseek/groq/custom.`);if(!s.has(t)&&t!=="vllm"&&t!=="custom"&&!ct(t)&&!(n?.apiKey||"").trim())throw new Error(`No API key configured for provider '${t}'. Run 'everclaw onboard' or edit ${at}.`);return t==="custom"||ct(t)?new cr(n?.apiKey||r?.apiKey||"no-key",kn(o,e)||r?.baseUrl||"http://localhost:8000/v1",e,{providerLabel:r?.name??t,apiFormat:r?.apiFormat,extraHeaders:r?.extraHeaders??n?.extraHeaders??null}):t==="gemini"?new dr(n?.apiKey||"",kn(o,e),e):new ur(n?.apiKey??null,kn(o,e),e,t)}sn();var mr=class extends W{constructor(t,n,r,s,i,a){super();this.serverName=t;this.remoteName=n;this.manager=a;this.name=r,this.description=s,this.parameters=i}name;description;parameters;validateParams(t){return[]}async execute(t,n){return this.manager.callTool(this.serverName,this.remoteName,t,n)}};function eo(o){return o&&o.replace(/<think>[\s\S]*?<\/think>/g,"").trim()||null}function ja(o){if(!o)return null;let e=o.match(/<think>([\s\S]*?)<\/think>/);return e?(e[1]||"").trim():null}function Fa(o,e=200){let t=typeof o=="string"?o.trim().replace(/\s+/g," "):"";return t?t.length>e?`${t.slice(0,Math.max(0,e-1)).trimEnd()}\u2026`:t:null}var Nt=class o{constructor(e){this.input=e;let t=cs.resolve(e.workspace);this.context=new gt(t,e.skillScannerConfig,e.skillScanner);let n=e.sessionManager??new Qe(t);this.sessions=n,this.lifecycle=e.lifecycle??Ye();let r=e.model??e.provider.getDefaultModel();this.subagents=new or(e.bus,e.subagentExecutor??new nr,e.subagentInlineExecutor??new rr(n),{workspace:t,model:r,temperature:e.temperature??.1,maxTokens:e.maxTokens??4096,braveApiKey:e.braveApiKey??null,execConfig:e.execConfig??{timeout:60,pathAppend:""},restrictToWorkspace:!!e.restrictToWorkspace}),this.tools=this.createToolRegistry();let s=Math.max(0,e.overloadControl?.maxQueuedPerSession??o.DEFAULT_MAX_QUEUED_PER_SESSION);this.maxRequestsPerWindow=Math.max(1,e.overloadControl?.maxRequestsPerWindow??o.DEFAULT_MAX_REQUESTS_PER_WINDOW),this.rateLimitWindowMs=Math.max(1,e.overloadControl?.rateLimitWindowMs??o.DEFAULT_RATE_LIMIT_WINDOW_MS),this.runtime=new sr(Math.max(1,e.maxConcurrentSessions??4),s)}context;sessions;tools;subagents;runtime;lifecycle;running=!1;acceptingWork=!0;consolidating=new Set;activeControllers=new Map;activeDispatches=new Set;mcpManager=new on;recentInboundBySession=new Map;static CANCELLED_SENTINEL=Symbol("cancelled");static TOOL_RESULT_MAX_CHARS=500;static SHUTDOWN_MESSAGE="Gateway is shutting down. Please try again later.";static SESSION_BUSY_MESSAGE="This session is busy right now. Please wait for the current response before sending more messages.";static DEFAULT_MAX_QUEUED_PER_SESSION=1;static DEFAULT_MAX_REQUESTS_PER_WINDOW=6;static DEFAULT_RATE_LIMIT_WINDOW_MS=3e4;maxRequestsPerWindow;rateLimitWindowMs;rateLimited=0;lastRateLimitedAt=null;get model(){return this.input.model??this.input.provider.getDefaultModel()}get channelsConfig(){return this.input.channelsConfig}isToolCallingEnabled(e=this.model){if(!this.input.loadConfig)return!0;let t=this.input.loadConfig(),n=xn(t,e);return n&&typeof n.toolCalling=="boolean"?n.toolCalling:!0}isReasoningEnabled(e=this.model){if(!this.input.loadConfig)return!1;let t=this.input.loadConfig(),n=xn(t,e);return n&&typeof n.reasoning=="boolean"?n.reasoning:!1}isImageOutputEnabled(e=this.model){if(!this.input.loadConfig)return!1;let t=this.input.loadConfig(),n=xn(t,e);return n&&typeof n.imageOutput=="boolean"?n.imageOutput:!1}resolveTurnModel(e){let t=String(e?._model??"").trim(),n=String(e?._provider??"").trim();if(!t||!this.input.loadConfig)return{model:this.model,provider:this.input.provider};let r=structuredClone(this.input.loadConfig());return r.agents.defaults.model=t,r.agents.defaults.provider=n||"auto",{model:t,provider:_e(r)}}getRuntimeState(){let e=this.runtime.snapshot();return{running:this.running,acceptingWork:this.acceptingWork,maxConcurrentSessions:e.maxConcurrency,activeSessions:e.running,queuedSessions:e.sessions.filter(t=>t.queued>0).length,queuedMessages:e.queued,subagents:this.subagents.getRunningCount(),sessions:e.sessions,overload:{maxQueuedPerSession:e.maxQueuedPerKey,maxRequestsPerWindow:this.maxRequestsPerWindow,rateLimitWindowMs:this.rateLimitWindowMs,rateLimited:this.rateLimited,backpressured:e.backpressured,lastRateLimitedAt:this.lastRateLimitedAt,lastBackpressureAt:e.lastBackpressureAt}}}rateLimitMessage(e){return`This session is receiving messages too quickly. Please wait ${Math.max(1,Math.ceil(e/1e3))}s and try again.`}pruneRecentInbound(e,t=Date.now()){let n=(this.recentInboundBySession.get(e)??[]).filter(r=>t-r<this.rateLimitWindowMs);return n.length?this.recentInboundBySession.set(e,n):this.recentInboundBySession.delete(e),n}checkRateLimit(e){let t=Date.now(),n=this.pruneRecentInbound(e,t);if(n.length>=this.maxRequestsPerWindow){this.rateLimited+=1,this.lastRateLimitedAt=new Date(t).toISOString();let r=n[0];return r!=null?Math.max(1,this.rateLimitWindowMs-(t-r)):this.rateLimitWindowMs}return n.push(t),this.recentInboundBySession.set(e,n),null}makeDirectResult(e,t,n){return n==null?{outcome:e,content:t}:{outcome:e,content:t,retryAfterMs:n}}rejectIfOverloaded(e,t){if(e.channel==="system")return null;let n=this.checkRateLimit(t);return n==null?null:this.makeDirectResult("rate_limited",this.rateLimitMessage(n),n)}mapRuntimeResult(e){return e.status==="cancelled"?this.makeDirectResult("cancelled","Task was cancelled."):e.status==="rejected"?this.makeDirectResult("backpressure",o.SESSION_BUSY_MESSAGE):this.makeDirectResult("completed",e.value?.content??"")}async publishDirectResult(e,t,n){let r=t.outcome==="rate_limited"?{...n,_overload:t.outcome,_retry_after_ms:t.retryAfterMs??0}:t.outcome==="backpressure"?{...n,_overload:t.outcome}:n??{};await this.input.bus.publishOutbound({channel:e.channel,chatId:e.chatId,content:t.content,metadata:r})}async withAgentTurnLifecycle(e,t,n,r){await We(this.lifecycle.beforeAgentTurn,"beforeAgentTurn",{message:e,sessionKey:t,trigger:n});let s=null,i=!1,a=null;try{let l=await r();return s=l.response,i=l.cancelled,s}catch(l){a=l;try{let c=this.sessions.getOrCreate(t);c.messages.push({role:"assistant",content:null,_error:String(l),timestamp:new Date().toISOString()}),c.updatedAt=new Date().toISOString(),this.sessions.save(c)}catch(c){console.error(`[agent] failed to persist error turn for ${t}:`,c)}throw l}finally{await We(this.lifecycle.afterAgentTurn,"afterAgentTurn",{message:e,sessionKey:t,trigger:n,response:s,cancelled:i,error:a})}}createToolRegistry(e){let t=this.input.loadConfig?.(),n=t?.tools?.browserRelay?.enabled??!1,r=t?.tools?.chromeSession?.enabled??!1,s={workspace:cs.resolve(this.input.workspace),restrictToWorkspace:!!this.input.restrictToWorkspace,braveApiKey:this.input.braveApiKey??null,execConfig:this.input.execConfig??{timeout:60,pathAppend:""},bus:this.input.bus,subagents:this.subagents,sessionManager:this.sessions};if(e&&(s.turn=e),this.input.cronService&&(s.cronService=this.input.cronService),this.input.rtkConfig&&(s.rtkConfig=this.input.rtkConfig),this.input.rtkService&&(s.rtkService=this.input.rtkService),this.input.browserRelay&&n&&(s.browserRelay=this.input.browserRelay),r){let a=this.input.chromeSessionConfig??t?.tools?.chromeSession;a&&(s.chromeSessionConfig=a)}let i=tr(s);return this.input.guardEngine&&i.setGuardEngine(this.input.guardEngine),i}toolHint(e){return e.map(t=>{let n=Object.values(t.arguments??{})[0];return typeof n!="string"?t.name:n.length>40?`${t.name}("${n.slice(0,40)}...")`:`${t.name}("${n}")`}).join(", ")}async runAgentLoop(e,t,n,r=()=>!0,s,i){let a=[...e],l=null,c=[],u=this.input.maxIterations??40,g=i?.model??this.model,h=i?.provider??this.input.provider,T=this.isToolCallingEnabled(g),v=this.isReasoningEnabled(g),d=this.isImageOutputEnabled(g),b=T?t.getDefinitions():void 0,k=AbortSignal.timeout(12e4),U=s?AbortSignal.any([s,k]):k;for(let L=0;L<u;L++){if(!r())return{finalContent:null,toolsUsed:c,messages:a,cancelled:!0,terminal:!1};Y(s);let N;try{N=await h.chat({messages:a,...b?{tools:b}:{},model:g,temperature:this.input.temperature??.1,maxTokens:this.input.maxTokens??4096,...v?{reasoning:!0}:{},...d?{imageOutput:!0}:{},signal:U})}catch(F){if(te(F)){if(s?.aborted)throw F;return{finalContent:null,toolsUsed:c,messages:a,cancelled:!0,terminal:!1}}throw F}if(Y(s),!r())return{finalContent:null,toolsUsed:c,messages:a,cancelled:!0,terminal:!1};let z=N.reasoningContent||ja(N.content);if(z&&n&&r()&&await n(z,{event:"thinking",thinkingContent:z,toolHint:!1}),N.toolCalls.length){let F=eo(N.content);n&&F&&r()&&await n(F,{event:"answer",toolHint:!1});let ae=N.toolCalls.map(J=>({id:J.id,type:"function",function:{name:J.name,arguments:JSON.stringify(J.arguments)}}));n&&r()&&await n(this.toolHint(N.toolCalls),{event:"tool_calls",toolHint:!0,tool_calls:ae.map(J=>({...J,status:"running"}))}),this.context.addAssistantMessage(a,F,ae,z);for(let J of N.toolCalls){if(!r())return{finalContent:null,toolsUsed:c,messages:a,cancelled:!0,terminal:!1};Y(s),c.push(J.name);let Z=await t.execute(J.name,J.arguments,s?{signal:s}:{});if(Y(s),!r())return{finalContent:null,toolsUsed:c,messages:a,cancelled:!0,terminal:!1};let A=Z.kind==="cancelled"?"Task was cancelled.":Z.content;if(this.context.addToolResult(a,J.id,J.name,A),n&&r()&&await n(A,{event:"tool_result",toolHint:!0,tool_call:{id:J.id,type:"function",function:{name:J.name,arguments:JSON.stringify(J.arguments)},status:"completed",resultPreview:Fa(A,200)??null}}),Z.kind==="terminal")return{finalContent:null,toolsUsed:c,messages:a,cancelled:!1,terminal:!0};if(Z.kind==="cancelled")return{finalContent:null,toolsUsed:c,messages:a,cancelled:!0,terminal:!1};if(Z.kind==="error"&&!Z.retryable)break}}else{l=eo(N.content),l&&n&&r()&&await n(l,{event:"answer",toolHint:!1}),this.context.addAssistantMessage(a,l,void 0,z);break}}return l==null&&(l=`I reached the maximum number of tool call iterations (${u}) without completing the task.`),{finalContent:l,toolsUsed:c,messages:a,cancelled:!1,terminal:!1}}async run(){for(this.running=!0,this.acceptingWork=!0;this.running;){let e=await this.input.bus.consumeInbound();if(!this.running||e.metadata?._shutdown)break;if(!this.acceptingWork){await this.input.bus.publishOutbound({channel:e.channel,chatId:e.chatId,content:o.SHUTDOWN_MESSAGE,metadata:{_shutdown:!0}});continue}if((typeof e.content=="string"?e.content.trim():(e.content.find(r=>r.type==="text")?.text??"").trim()).toLowerCase()==="/stop"){await this.handleStop(e);continue}let n=this.dispatch(e).catch(r=>console.error(`[agent] dispatch error for ${Zr(e)}:`,r));this.activeDispatches.add(n),n.finally(()=>this.activeDispatches.delete(n))}}stop(){this.running=!1}beginShutdown(){this.acceptingWork=!1}async shutdown(){this.beginShutdown(),this.running=!1;let e=await this.stopAllSessions();return this.activeDispatches.size>0&&await Promise.race([Promise.allSettled(this.activeDispatches),new Promise(n=>setTimeout(n,1e4))]),await this.mcpManager.closeAll(),await this.input.bus.publishInbound({channel:"system",senderId:"system",chatId:"gateway:shutdown",content:"",metadata:{_shutdown:!0}}),e}async processDirect(e,t="cli:direct",n="cli",r="direct",s){return(await this.processDirectResult(e,t,n,r,s)).content}async processDirectResult(e,t="cli:direct",n="cli",r="direct",s,i){let a={channel:n,senderId:"user",chatId:r,content:e,sessionKeyOverride:t,...i?{metadata:i}:{}};if((typeof e=="string"?e:e.find(g=>g.type==="text")?.text??"").trim().toLowerCase()==="/stop"){let g=await this.stopSession(t);return this.makeDirectResult("completed",g?`Stopped ${g} task(s).`:"No active task to stop.")}if(!this.acceptingWork)return this.makeDirectResult("shutdown",o.SHUTDOWN_MESSAGE);let c=this.rejectIfOverloaded(a,t);if(c)return c;let u=await this.runtime.enqueue(t,({isCurrent:g})=>this.withSessionController(t,h=>this.processMessage(a,t,s,g,h,"direct")));return u.status==="completed"&&u.value===o.CANCELLED_SENTINEL?this.makeDirectResult("cancelled","Task was cancelled."):this.mapRuntimeResult(u)}async dispatch(e){try{if(!this.acceptingWork)return;let t=this.resolveSessionContext(e),n=this.rejectIfOverloaded(e,t.key);if(n){await this.publishDirectResult(t,n,e.metadata);return}let r=await this.runtime.enqueue(t.key,async({isCurrent:s})=>{try{let i=await this.withSessionController(t.key,a=>this.processMessage(e,t.key,void 0,s,a,"queued"));return i===o.CANCELLED_SENTINEL?s()?{channel:t.channel,chatId:t.chatId,content:"Task was cancelled.",metadata:{_cancelled:!0}}:null:i}catch{return s()?{channel:t.channel,chatId:t.chatId,content:"Sorry, I encountered an error."}:null}},{bypassCapacity:e.channel==="system"});if(r.status==="rejected"){await this.publishDirectResult(t,this.makeDirectResult("backpressure",o.SESSION_BUSY_MESSAGE),e.metadata);return}if(r.status==="cancelled")return;r.value?await this.input.bus.publishOutbound(r.value):e.channel==="cli"&&await this.input.bus.publishOutbound({channel:e.channel,chatId:e.chatId,content:"",metadata:e.metadata??{}})}catch(t){console.error(`[agent] dispatch error (channel=${e.channel}, chatId=${e.chatId}):`,t)}}async handleStop(e){let t=await this.stopSession(this.resolveSessionContext(e).key);await this.input.bus.publishOutbound({channel:e.channel,chatId:e.chatId,content:t?`Stopped ${t} task(s).`:"No active task to stop."})}async stopSession(e){let t=this.runtime.cancel(e);t.running&&this.abortSession(e);let n=await this.subagents.cancelBySession(e);return Number(t.running)+t.queued+n}async stopAllSessions(){let e=0;for(let t of this.runtime.snapshot().sessions){let n=this.runtime.cancel(t.key);n.running&&this.abortSession(t.key),e+=Number(n.running)+n.queued}return e+await this.subagents.cancelAll()}abortSession(e){this.activeControllers.get(e)?.abort()}async withSessionController(e,t){let n=new AbortController;this.activeControllers.set(e,n);try{return await t(n.signal)}catch(r){if(te(r))return o.CANCELLED_SENTINEL;throw r}finally{this.activeControllers.get(e)===n&&this.activeControllers.delete(e)}}resolveSessionContext(e,t){let n=e.metadata?.message_id;if(e.channel==="system"){let r=String(e.chatId),s=r.includes(":"),i=s?r.split(/:(.*)/s,2)[0]:"cli",a=s?r.split(/:(.*)/s,2)[1]:r,l={key:`${i}:${a}`,channel:i,chatId:a};return n&&(l.messageId=n),l}return{key:t??Zr(e),channel:e.channel,chatId:e.chatId,...n?{messageId:n}:{}}}memoryNamespace(e){return e.includes(":")&&e.replace(/:/g,"_")||void 0}async consolidateMemory(e,t=!1,n=this.input.provider,r=this.model){return this.context.getMemoryStore(this.memoryNamespace(e.key)).consolidate(e,n,r,{archiveAll:t,memoryWindow:this.input.memoryWindow??100})}saveTurn(e,t,n,r){let s=t.slice(n);for(let i=0;i<s.length;i++){let l={...s[i]};l.role==="assistant"&&typeof l.content=="string"&&(l.content=eo(l.content)),l.role==="tool"&&typeof l.content=="string"&&l.content.length>o.TOOL_RESULT_MAX_CHARS&&(l._full_content=l.content,l.content=`${l.content.slice(0,o.TOOL_RESULT_MAX_CHARS)}
266
+ ${r==="groq"?"Try a Groq-supported model like llama-3.3-70b-versatile or openai/gpt-oss-120b. You can run `everclaw doctor`.":"Check your model id and provider access. You can run `everclaw doctor`."}`,toolCalls:[],finishReason:"error",usage:{},reasoningContent:null}:{content:`Error calling LLM: ${h}`,toolCalls:[],finishReason:"error",usage:{},reasoningContent:null}}let c=l.choices?.[0]?.message?l.choices[0]:null;if(!c)return{content:`Error calling LLM: ${JSON.stringify(l)}`,toolCalls:[],finishReason:"error",usage:{},reasoningContent:null};let u=(c.message.tool_calls??[]).map(g=>({id:Oa(9),name:g.function.name,arguments:typeof g.function.arguments=="string"?JSON.parse(g.function.arguments||"{}"):g.function.arguments}));return{content:c.message.content??null,toolCalls:u,finishReason:c.finish_reason??"stop",usage:l.usage??{},reasoningContent:c.message.reasoning_content??null}}catch(r){if(te(r))throw r;return{content:`Error calling LLM: ${String(r)}`,toolCalls:[],finishReason:"error",usage:{},reasoningContent:null}}}};function _e(o){let e=o.agents.defaults.model,t=Xe(o,e),n=_o(o,e),r=t&&ct(t)?Ct(o,t,e):null,s=new Set(["openai_codex","github_copilot"]),i=new Set(["anthropic"]);if(!t)throw new Error("No provider could be resolved from config. Run `everclaw onboard` and set provider/model/API key.");if(ct(t)&&!r)throw new Error(`Custom provider '${t}' could not be found. Check ${at}.`);if(i.has(t))throw new Error(`Provider '${t}' is not supported in this TypeScript port yet. Use openrouter/openai/deepseek/groq/custom.`);if(!s.has(t)&&t!=="vllm"&&t!=="custom"&&!ct(t)&&!(n?.apiKey||"").trim())throw new Error(`No API key configured for provider '${t}'. Run 'everclaw onboard' or edit ${at}.`);return t==="custom"||ct(t)?new cr(n?.apiKey||r?.apiKey||"no-key",kn(o,e)||r?.baseUrl||"http://localhost:8000/v1",e,{providerLabel:r?.name??t,apiFormat:r?.apiFormat,extraHeaders:r?.extraHeaders??n?.extraHeaders??null}):t==="gemini"?new dr(n?.apiKey||"",kn(o,e),e):new ur(n?.apiKey??null,kn(o,e),e,t)}sn();var mr=class extends W{constructor(t,n,r,s,i,a){super();this.serverName=t;this.remoteName=n;this.manager=a;this.name=r,this.description=s,this.parameters=i}name;description;parameters;validateParams(t){return[]}async execute(t,n){return this.manager.callTool(this.serverName,this.remoteName,t,n)}};function eo(o){return o&&o.replace(/<think>[\s\S]*?<\/think>/g,"").trim()||null}function ja(o){if(!o)return null;let e=o.match(/<think>([\s\S]*?)<\/think>/);return e?(e[1]||"").trim():null}function Fa(o,e=200){let t=typeof o=="string"?o.trim().replace(/\s+/g," "):"";return t?t.length>e?`${t.slice(0,Math.max(0,e-1)).trimEnd()}\u2026`:t:null}var Nt=class o{constructor(e){this.input=e;let t=cs.resolve(e.workspace);this.context=new gt(t,e.skillScannerConfig,e.skillScanner);let n=e.sessionManager??new Qe(t);this.sessions=n,this.lifecycle=e.lifecycle??Ye();let r=e.model??e.provider.getDefaultModel();this.subagents=new or(e.bus,e.subagentExecutor??new nr,e.subagentInlineExecutor??new rr(n),{workspace:t,model:r,temperature:e.temperature??.1,maxTokens:e.maxTokens??4096,braveApiKey:e.braveApiKey??null,execConfig:e.execConfig??{timeout:60,pathAppend:""},restrictToWorkspace:!!e.restrictToWorkspace}),this.tools=this.createToolRegistry();let s=Math.max(0,e.overloadControl?.maxQueuedPerSession??o.DEFAULT_MAX_QUEUED_PER_SESSION);this.maxRequestsPerWindow=Math.max(1,e.overloadControl?.maxRequestsPerWindow??o.DEFAULT_MAX_REQUESTS_PER_WINDOW),this.rateLimitWindowMs=Math.max(1,e.overloadControl?.rateLimitWindowMs??o.DEFAULT_RATE_LIMIT_WINDOW_MS),this.runtime=new sr(Math.max(1,e.maxConcurrentSessions??4),s)}context;sessions;tools;subagents;runtime;lifecycle;running=!1;acceptingWork=!0;consolidating=new Set;activeControllers=new Map;activeDispatches=new Set;mcpManager=new on;recentInboundBySession=new Map;static CANCELLED_SENTINEL=Symbol("cancelled");static TOOL_RESULT_MAX_CHARS=500;static SHUTDOWN_MESSAGE="Gateway is shutting down. Please try again later.";static SESSION_BUSY_MESSAGE="This session is busy right now. Please wait for the current response before sending more messages.";static DEFAULT_MAX_QUEUED_PER_SESSION=1;static DEFAULT_MAX_REQUESTS_PER_WINDOW=6;static DEFAULT_RATE_LIMIT_WINDOW_MS=3e4;maxRequestsPerWindow;rateLimitWindowMs;rateLimited=0;lastRateLimitedAt=null;get model(){return this.input.model??this.input.provider.getDefaultModel()}get channelsConfig(){return this.input.channelsConfig}isToolCallingEnabled(e=this.model){if(!this.input.loadConfig)return!0;let t=this.input.loadConfig(),n=xn(t,e);return n&&typeof n.toolCalling=="boolean"?n.toolCalling:!0}isReasoningEnabled(e=this.model){if(!this.input.loadConfig)return!1;let t=this.input.loadConfig(),n=xn(t,e);return n&&typeof n.reasoning=="boolean"?n.reasoning:!1}isImageOutputEnabled(e=this.model){if(!this.input.loadConfig)return!1;let t=this.input.loadConfig(),n=xn(t,e);return n&&typeof n.imageOutput=="boolean"?n.imageOutput:!1}resolveTurnModel(e){let t=String(e?._model??"").trim(),n=String(e?._provider??"").trim();if(!t||!this.input.loadConfig)return{model:this.model,provider:this.input.provider};let r=structuredClone(this.input.loadConfig());return r.agents.defaults.model=t,r.agents.defaults.provider=n||"auto",{model:t,provider:_e(r)}}getRuntimeState(){let e=this.runtime.snapshot();return{running:this.running,acceptingWork:this.acceptingWork,maxConcurrentSessions:e.maxConcurrency,activeSessions:e.running,queuedSessions:e.sessions.filter(t=>t.queued>0).length,queuedMessages:e.queued,subagents:this.subagents.getRunningCount(),sessions:e.sessions,overload:{maxQueuedPerSession:e.maxQueuedPerKey,maxRequestsPerWindow:this.maxRequestsPerWindow,rateLimitWindowMs:this.rateLimitWindowMs,rateLimited:this.rateLimited,backpressured:e.backpressured,lastRateLimitedAt:this.lastRateLimitedAt,lastBackpressureAt:e.lastBackpressureAt}}}rateLimitMessage(e){return`This session is receiving messages too quickly. Please wait ${Math.max(1,Math.ceil(e/1e3))}s and try again.`}pruneRecentInbound(e,t=Date.now()){let n=(this.recentInboundBySession.get(e)??[]).filter(r=>t-r<this.rateLimitWindowMs);return n.length?this.recentInboundBySession.set(e,n):this.recentInboundBySession.delete(e),n}checkRateLimit(e){let t=Date.now(),n=this.pruneRecentInbound(e,t);if(n.length>=this.maxRequestsPerWindow){this.rateLimited+=1,this.lastRateLimitedAt=new Date(t).toISOString();let r=n[0];return r!=null?Math.max(1,this.rateLimitWindowMs-(t-r)):this.rateLimitWindowMs}return n.push(t),this.recentInboundBySession.set(e,n),null}makeDirectResult(e,t,n){return n==null?{outcome:e,content:t}:{outcome:e,content:t,retryAfterMs:n}}rejectIfOverloaded(e,t){if(e.channel==="system")return null;let n=this.checkRateLimit(t);return n==null?null:this.makeDirectResult("rate_limited",this.rateLimitMessage(n),n)}mapRuntimeResult(e){return e.status==="cancelled"?this.makeDirectResult("cancelled","Task was cancelled."):e.status==="rejected"?this.makeDirectResult("backpressure",o.SESSION_BUSY_MESSAGE):this.makeDirectResult("completed",e.value?.content??"")}async publishDirectResult(e,t,n){let r=t.outcome==="rate_limited"?{...n,_overload:t.outcome,_retry_after_ms:t.retryAfterMs??0}:t.outcome==="backpressure"?{...n,_overload:t.outcome}:n??{};await this.input.bus.publishOutbound({channel:e.channel,chatId:e.chatId,content:t.content,metadata:r})}async withAgentTurnLifecycle(e,t,n,r){await We(this.lifecycle.beforeAgentTurn,"beforeAgentTurn",{message:e,sessionKey:t,trigger:n});let s=null,i=!1,a=null;try{let l=await r();return s=l.response,i=l.cancelled,s}catch(l){a=l;try{let c=this.sessions.getOrCreate(t);c.messages.push({role:"assistant",content:null,_error:String(l),timestamp:new Date().toISOString()}),c.updatedAt=new Date().toISOString(),this.sessions.save(c)}catch(c){console.error(`[agent] failed to persist error turn for ${t}:`,c)}throw l}finally{await We(this.lifecycle.afterAgentTurn,"afterAgentTurn",{message:e,sessionKey:t,trigger:n,response:s,cancelled:i,error:a})}}createToolRegistry(e){let t=this.input.loadConfig?.(),n=t?.tools?.browserRelay?.enabled??!1,r=t?.tools?.chromeSession?.enabled??!1,s={workspace:cs.resolve(this.input.workspace),restrictToWorkspace:!!this.input.restrictToWorkspace,braveApiKey:this.input.braveApiKey??null,execConfig:this.input.execConfig??{timeout:60,pathAppend:""},bus:this.input.bus,subagents:this.subagents,sessionManager:this.sessions};if(e&&(s.turn=e),this.input.cronService&&(s.cronService=this.input.cronService),this.input.rtkConfig&&(s.rtkConfig=this.input.rtkConfig),this.input.rtkService&&(s.rtkService=this.input.rtkService),this.input.browserRelay&&n&&(s.browserRelay=this.input.browserRelay),r){let a=this.input.chromeSessionConfig??t?.tools?.chromeSession;a&&(s.chromeSessionConfig=a)}let i=tr(s);return this.input.guardEngine&&i.setGuardEngine(this.input.guardEngine),i}toolHint(e){return e.map(t=>{let n=Object.values(t.arguments??{})[0];return typeof n!="string"?t.name:n.length>40?`${t.name}("${n.slice(0,40)}...")`:`${t.name}("${n}")`}).join(", ")}async runAgentLoop(e,t,n,r=()=>!0,s,i){let a=[...e],l=null,c=[],u=this.input.maxIterations??40,g=i?.model??this.model,h=i?.provider??this.input.provider,T=this.isToolCallingEnabled(g),v=this.isReasoningEnabled(g),d=this.isImageOutputEnabled(g),b=T?t.getDefinitions():void 0,k=AbortSignal.timeout(12e4),U=s?AbortSignal.any([s,k]):k;for(let L=0;L<u;L++){if(!r())return{finalContent:null,toolsUsed:c,messages:a,cancelled:!0,terminal:!1};Y(s);let N;try{N=await h.chat({messages:a,...b?{tools:b}:{},model:g,temperature:this.input.temperature??.1,maxTokens:this.input.maxTokens??4096,...v?{reasoning:!0}:{},...d?{imageOutput:!0}:{},signal:U})}catch(B){if(te(B)){if(s?.aborted)throw B;return{finalContent:null,toolsUsed:c,messages:a,cancelled:!0,terminal:!1}}throw B}if(Y(s),!r())return{finalContent:null,toolsUsed:c,messages:a,cancelled:!0,terminal:!1};let z=N.reasoningContent||ja(N.content);if(z&&n&&r()&&await n(z,{event:"thinking",thinkingContent:z,toolHint:!1}),N.toolCalls.length){let B=eo(N.content);n&&B&&r()&&await n(B,{event:"answer",toolHint:!1});let ae=N.toolCalls.map(J=>({id:J.id,type:"function",function:{name:J.name,arguments:JSON.stringify(J.arguments)}}));n&&r()&&await n(this.toolHint(N.toolCalls),{event:"tool_calls",toolHint:!0,tool_calls:ae.map(J=>({...J,status:"running"}))}),this.context.addAssistantMessage(a,B,ae,z);for(let J of N.toolCalls){if(!r())return{finalContent:null,toolsUsed:c,messages:a,cancelled:!0,terminal:!1};Y(s),c.push(J.name);let Z=await t.execute(J.name,J.arguments,s?{signal:s}:{});if(Y(s),!r())return{finalContent:null,toolsUsed:c,messages:a,cancelled:!0,terminal:!1};let A=Z.kind==="cancelled"?"Task was cancelled.":Z.content;if(this.context.addToolResult(a,J.id,J.name,A),n&&r()&&await n(A,{event:"tool_result",toolHint:!0,tool_call:{id:J.id,type:"function",function:{name:J.name,arguments:JSON.stringify(J.arguments)},status:"completed",resultPreview:Fa(A,200)??null}}),Z.kind==="terminal")return{finalContent:null,toolsUsed:c,messages:a,cancelled:!1,terminal:!0};if(Z.kind==="cancelled")return{finalContent:null,toolsUsed:c,messages:a,cancelled:!0,terminal:!1};if(Z.kind==="error"&&!Z.retryable)break}}else{l=eo(N.content),l&&n&&r()&&await n(l,{event:"answer",toolHint:!1}),this.context.addAssistantMessage(a,l,void 0,z);break}}return l==null&&(l=`I reached the maximum number of tool call iterations (${u}) without completing the task.`),{finalContent:l,toolsUsed:c,messages:a,cancelled:!1,terminal:!1}}async run(){for(this.running=!0,this.acceptingWork=!0;this.running;){let e=await this.input.bus.consumeInbound();if(!this.running||e.metadata?._shutdown)break;if(!this.acceptingWork){await this.input.bus.publishOutbound({channel:e.channel,chatId:e.chatId,content:o.SHUTDOWN_MESSAGE,metadata:{_shutdown:!0}});continue}if((typeof e.content=="string"?e.content.trim():(e.content.find(r=>r.type==="text")?.text??"").trim()).toLowerCase()==="/stop"){await this.handleStop(e);continue}let n=this.dispatch(e).catch(r=>console.error(`[agent] dispatch error for ${Zr(e)}:`,r));this.activeDispatches.add(n),n.finally(()=>this.activeDispatches.delete(n))}}stop(){this.running=!1}beginShutdown(){this.acceptingWork=!1}async shutdown(){this.beginShutdown(),this.running=!1;let e=await this.stopAllSessions();return this.activeDispatches.size>0&&await Promise.race([Promise.allSettled(this.activeDispatches),new Promise(n=>setTimeout(n,1e4))]),await this.mcpManager.closeAll(),await this.input.bus.publishInbound({channel:"system",senderId:"system",chatId:"gateway:shutdown",content:"",metadata:{_shutdown:!0}}),e}async processDirect(e,t="cli:direct",n="cli",r="direct",s){return(await this.processDirectResult(e,t,n,r,s)).content}async processDirectResult(e,t="cli:direct",n="cli",r="direct",s,i){let a={channel:n,senderId:"user",chatId:r,content:e,sessionKeyOverride:t,...i?{metadata:i}:{}};if((typeof e=="string"?e:e.find(g=>g.type==="text")?.text??"").trim().toLowerCase()==="/stop"){let g=await this.stopSession(t);return this.makeDirectResult("completed",g?`Stopped ${g} task(s).`:"No active task to stop.")}if(!this.acceptingWork)return this.makeDirectResult("shutdown",o.SHUTDOWN_MESSAGE);let c=this.rejectIfOverloaded(a,t);if(c)return c;let u=await this.runtime.enqueue(t,({isCurrent:g})=>this.withSessionController(t,h=>this.processMessage(a,t,s,g,h,"direct")));return u.status==="completed"&&u.value===o.CANCELLED_SENTINEL?this.makeDirectResult("cancelled","Task was cancelled."):this.mapRuntimeResult(u)}async dispatch(e){try{if(!this.acceptingWork)return;let t=this.resolveSessionContext(e),n=this.rejectIfOverloaded(e,t.key);if(n){await this.publishDirectResult(t,n,e.metadata);return}let r=await this.runtime.enqueue(t.key,async({isCurrent:s})=>{try{let i=await this.withSessionController(t.key,a=>this.processMessage(e,t.key,void 0,s,a,"queued"));return i===o.CANCELLED_SENTINEL?s()?{channel:t.channel,chatId:t.chatId,content:"Task was cancelled.",metadata:{_cancelled:!0}}:null:i}catch{return s()?{channel:t.channel,chatId:t.chatId,content:"Sorry, I encountered an error."}:null}},{bypassCapacity:e.channel==="system"});if(r.status==="rejected"){await this.publishDirectResult(t,this.makeDirectResult("backpressure",o.SESSION_BUSY_MESSAGE),e.metadata);return}if(r.status==="cancelled")return;r.value?await this.input.bus.publishOutbound(r.value):e.channel==="cli"&&await this.input.bus.publishOutbound({channel:e.channel,chatId:e.chatId,content:"",metadata:e.metadata??{}})}catch(t){console.error(`[agent] dispatch error (channel=${e.channel}, chatId=${e.chatId}):`,t)}}async handleStop(e){let t=await this.stopSession(this.resolveSessionContext(e).key);await this.input.bus.publishOutbound({channel:e.channel,chatId:e.chatId,content:t?`Stopped ${t} task(s).`:"No active task to stop."})}async stopSession(e){let t=this.runtime.cancel(e);t.running&&this.abortSession(e);let n=await this.subagents.cancelBySession(e);return Number(t.running)+t.queued+n}async stopAllSessions(){let e=0;for(let t of this.runtime.snapshot().sessions){let n=this.runtime.cancel(t.key);n.running&&this.abortSession(t.key),e+=Number(n.running)+n.queued}return e+await this.subagents.cancelAll()}abortSession(e){this.activeControllers.get(e)?.abort()}async withSessionController(e,t){let n=new AbortController;this.activeControllers.set(e,n);try{return await t(n.signal)}catch(r){if(te(r))return o.CANCELLED_SENTINEL;throw r}finally{this.activeControllers.get(e)===n&&this.activeControllers.delete(e)}}resolveSessionContext(e,t){let n=e.metadata?.message_id;if(e.channel==="system"){let r=String(e.chatId),s=r.includes(":"),i=s?r.split(/:(.*)/s,2)[0]:"cli",a=s?r.split(/:(.*)/s,2)[1]:r,l={key:`${i}:${a}`,channel:i,chatId:a};return n&&(l.messageId=n),l}return{key:t??Zr(e),channel:e.channel,chatId:e.chatId,...n?{messageId:n}:{}}}memoryNamespace(e){return e.includes(":")&&e.replace(/:/g,"_")||void 0}async consolidateMemory(e,t=!1,n=this.input.provider,r=this.model){return this.context.getMemoryStore(this.memoryNamespace(e.key)).consolidate(e,n,r,{archiveAll:t,memoryWindow:this.input.memoryWindow??100})}saveTurn(e,t,n,r){let s=t.slice(n);for(let i=0;i<s.length;i++){let l={...s[i]};l.role==="assistant"&&typeof l.content=="string"&&(l.content=eo(l.content)),l.role==="tool"&&typeof l.content=="string"&&l.content.length>o.TOOL_RESULT_MAX_CHARS&&(l._full_content=l.content,l.content=`${l.content.slice(0,o.TOOL_RESULT_MAX_CHARS)}
267
267
  ... (truncated)`),!(l.role==="user"&&typeof l.content=="string"&&l.content.startsWith(gt.RUNTIME_CONTEXT_TAG))&&(l.timestamp||(l.timestamp=new Date().toISOString()),l.role==="assistant"&&r?.length&&i===s.length-1&&(l.tools_used=r),e.messages.push(l))}e.updatedAt=new Date().toISOString()}sanitizeInput(e,t){if(!t.security?.enabled||!t.security.inputSanitizer?.enabled)return e;let n=new lr(t.security.inputSanitizer);return typeof e=="string"?n.sanitize(e).sanitized:e.map(r=>{if(r.type==="text"){let s=n.sanitize(r.text);return{...r,text:s.sanitized}}return r})}async resolveCommand(e,t,n,r){return e==="/new"?t.messages.length&&!await this.consolidateMemory(t,!0,r.provider,r.model)?{response:{channel:n.channel,chatId:n.chatId,content:"Memory archival failed, session not cleared. Please try again."},cancelled:!1}:(t.clear(),this.sessions.save(t),this.sessions.invalidate(t.key),{response:{channel:n.channel,chatId:n.chatId,content:"New session started."},cancelled:!1}):e==="/help"?{response:{channel:n.channel,chatId:n.chatId,content:`everclaw commands:
268
268
  /new - Start a new conversation
269
269
  /stop - Stop the current task
270
- /help - Show available commands`},cancelled:!1}:null}async prepareTurnTools(e,t,n){let r=this.createToolRegistry(t);if(n.length&&e?.tools?.mcpServers){this.mcpManager.updateConfig(e.tools.mcpServers);for(let s of n)try{let i=await this.mcpManager.getServerTools(s);for(let a of i)r.register(new mr(a.serverName,a.remoteName,a.proxyName,a.description,a.inputSchema,this.mcpManager))}catch(i){console.warn(`MCP: failed to connect to '${s}': ${String(i)}`)}}return r}buildTurnPrompt(e,t,n,r){let s=e.getHistory(this.input.memoryWindow??100),i=this.sanitizeInput(t.content,n),a=this.memoryNamespace(e.key),l={history:s,currentMessage:i,channel:t.channel,chatId:t.chatId};return a&&(l.memoryNamespace=a),t.media&&(l.media=t.media),r.length&&(l.skillNames=r),{messages:this.context.buildMessages(l),newMessageStartIndex:1+s.length}}commitTurn(e,t,n,r){this.saveTurn(e,t,n,r),this.sessions.save(e)}async processMessage(e,t,n,r=()=>!0,s,i="queued"){let a=this.resolveSessionContext(e,t),l=this.input.loadConfig?.()??structuredClone(fe);return this.withAgentTurnLifecycle(e,a.key,i,async()=>{let c=this.sessions.getOrCreate(a.key),u=this.resolveTurnModel(e.metadata);if(e.channel==="system"){let{messages:q,newMessageStartIndex:re}=this.buildTurnPrompt(c,e,l,[]),p=await this.prepareTurnTools(l,{...a,sessionKey:a.key,isCurrent:r},[]),{finalContent:m,messages:f,toolsUsed:w,cancelled:x,terminal:E}=await this.runAgentLoop(q,p,void 0,r,s,u);return x||!r()?{response:null,cancelled:!0}:(this.commitTurn(c,f,re,w),{response:{channel:a.channel,chatId:a.chatId,content:m??"Background task completed."},cancelled:!1})}let h=(typeof e.content=="string"?e.content:e.content.find(q=>q.type==="text")?.text??"").trim().toLowerCase(),T=await this.resolveCommand(h,c,e,u);if(T)return T;let d=c.messages.length-c.lastConsolidated>=(this.input.memoryWindow??100)&&!this.consolidating.has(c.key),b=Array.isArray(e.metadata?.skillNames)?e.metadata.skillNames:[],$=new Set(Object.keys(l?.tools?.mcpServers??{})),k=b.filter(q=>$.has(q)),U=b.filter(q=>!$.has(q)),L=await this.prepareTurnTools(l,{...a,sessionKey:a.key,isCurrent:r},k),{messages:N,newMessageStartIndex:z}=this.buildTurnPrompt(c,e,l,U),F=async(q,re)=>{if(!r())return;let p={...e.metadata,_progress:!0,_tool_hint:!!re?.toolHint};await this.input.bus.publishOutbound({channel:e.channel,chatId:e.chatId,content:q,metadata:p})},{finalContent:ae,messages:J,toolsUsed:Z,cancelled:A,terminal:I}=await this.runAgentLoop(N,L,n??F,r,s,u);if(A||!r())return{response:null,cancelled:!0};let j=ae??"I've completed processing but have no response to give.";if(this.commitTurn(c,J,z,Z),d){this.consolidating.add(c.key);try{await this.consolidateMemory(c,!1,u.provider,u.model)}finally{this.consolidating.delete(c.key)}}return I?{response:null,cancelled:!1}:{response:{channel:e.channel,chatId:e.chatId,content:j,metadata:e.metadata??{}},cancelled:!1}})}};Nr();pt();var Ba=1024*1024,Ga=300*1e3;function ds(o){return o==="scheduled-job"?"Scheduled job":"Background job"}function Ua(o,e,t){let n=ds(o);if(t.failureAttribution==="timeout")return`${n} timed out after ${Math.ceil(e/1e3)} seconds`;let r=[t.stdout.trim()?`STDOUT:
270
+ /help - Show available commands`},cancelled:!1}:null}async prepareTurnTools(e,t,n){let r=this.createToolRegistry(t);if(n.length&&e?.tools?.mcpServers){this.mcpManager.updateConfig(e.tools.mcpServers);for(let s of n)try{let i=await this.mcpManager.getServerTools(s);for(let a of i)r.register(new mr(a.serverName,a.remoteName,a.proxyName,a.description,a.inputSchema,this.mcpManager))}catch(i){console.warn(`MCP: failed to connect to '${s}': ${String(i)}`)}}return r}buildTurnPrompt(e,t,n,r){let s=e.getHistory(this.input.memoryWindow??100),i=this.sanitizeInput(t.content,n),a=this.memoryNamespace(e.key),l={history:s,currentMessage:i,channel:t.channel,chatId:t.chatId};return a&&(l.memoryNamespace=a),t.media&&(l.media=t.media),r.length&&(l.skillNames=r),{messages:this.context.buildMessages(l),newMessageStartIndex:1+s.length}}commitTurn(e,t,n,r){this.saveTurn(e,t,n,r),this.sessions.save(e)}async processMessage(e,t,n,r=()=>!0,s,i="queued"){let a=this.resolveSessionContext(e,t),l=this.input.loadConfig?.()??structuredClone(fe);return this.withAgentTurnLifecycle(e,a.key,i,async()=>{let c=this.sessions.getOrCreate(a.key),u=this.resolveTurnModel(e.metadata);if(e.channel==="system"){let{messages:q,newMessageStartIndex:re}=this.buildTurnPrompt(c,e,l,[]),p=await this.prepareTurnTools(l,{...a,sessionKey:a.key,isCurrent:r},[]),{finalContent:m,messages:f,toolsUsed:w,cancelled:x,terminal:E}=await this.runAgentLoop(q,p,void 0,r,s,u);return x||!r()?{response:null,cancelled:!0}:(this.commitTurn(c,f,re,w),{response:{channel:a.channel,chatId:a.chatId,content:m??"Background task completed."},cancelled:!1})}let h=(typeof e.content=="string"?e.content:e.content.find(q=>q.type==="text")?.text??"").trim().toLowerCase(),T=await this.resolveCommand(h,c,e,u);if(T)return T;let d=c.messages.length-c.lastConsolidated>=(this.input.memoryWindow??100)&&!this.consolidating.has(c.key),b=Array.isArray(e.metadata?.skillNames)?e.metadata.skillNames:[],$=new Set(Object.keys(l?.tools?.mcpServers??{})),k=b.filter(q=>$.has(q)),U=b.filter(q=>!$.has(q)),L=await this.prepareTurnTools(l,{...a,sessionKey:a.key,isCurrent:r},k),{messages:N,newMessageStartIndex:z}=this.buildTurnPrompt(c,e,l,U),B=async(q,re)=>{if(!r())return;let p={...e.metadata,_progress:!0,_tool_hint:!!re?.toolHint};await this.input.bus.publishOutbound({channel:e.channel,chatId:e.chatId,content:q,metadata:p})},{finalContent:ae,messages:J,toolsUsed:Z,cancelled:A,terminal:I}=await this.runAgentLoop(N,L,n??B,r,s,u);if(A||!r())return{response:null,cancelled:!0};let F=ae??"I've completed processing but have no response to give.";if(this.commitTurn(c,J,z,Z),d){this.consolidating.add(c.key);try{await this.consolidateMemory(c,!1,u.provider,u.model)}finally{this.consolidating.delete(c.key)}}return I?{response:null,cancelled:!1}:{response:{channel:e.channel,chatId:e.chatId,content:F,metadata:e.metadata??{}},cancelled:!1}})}};Nr();pt();var Ba=1024*1024,Ga=300*1e3;function ds(o){return o==="scheduled-job"?"Scheduled job":"Background job"}function Ua(o,e,t){let n=ds(o);if(t.failureAttribution==="timeout")return`${n} timed out after ${Math.ceil(e/1e3)} seconds`;let r=[t.stdout.trim()?`STDOUT:
271
271
  ${t.stdout.trim()}`:"",t.stderr.trim()?`STDERR:
272
272
  ${t.stderr.trim()}`:"",typeof t.exitCode=="number"?`Exit code: ${t.exitCode}`:"",t.signal?`Signal: ${t.signal}`:"",t.errorMessage?`Error: ${t.errorMessage}`:""].filter(Boolean).join(`
273
273
  `);return r?`${n} failed
@@ -297,14 +297,14 @@ ${r}`:`${n} failed`}function Wa(){let o=process.argv[1]??"";return Mt(o)}functio
297
297
 
298
298
  `).trim()||"Skill installed."}function ol(o){if(o.failureAttribution==="timeout")return`Skill install timed out after ${Math.round(hs/1e3)} seconds.`;let e=bs(o),t=typeof o.exitCode=="number"?`
299
299
  Exit code: ${o.exitCode}`:"",n=o.signal?`
300
- Signal: ${o.signal}`:"";return`${e||"Skill install failed."}${t}${n}`.trim()}$e();le();import{scrypt as sl,randomBytes as ws,timingSafeEqual as il}from"node:crypto";var Ss=64,ks=16384,xs=8,Cs=1,al=5,vs=300*1e3;function ll(){let o=ws(16);o[6]=o[6]&15|64,o[8]=o[8]&63|128;let e=o.toString("hex");return`${e.slice(0,8)}-${e.slice(8,12)}-${e.slice(12,16)}-${e.slice(16,20)}-${e.slice(20)}`}function Ts(o,e,t,n){let r=n??{};return new Promise((s,i)=>{sl(o,e,t,r,(a,l)=>{a?i(a):s(l)})})}async function cl(o,e){let t=e??ws(16),n=await Ts(o,t,Ss,{N:ks,r:xs,p:Cs});return`${t.toString("hex")}:${n.toString("hex")}`}async function dl(o,e){let t=e.split(":");if(t.length!==2)return!1;let n=Buffer.from(t[0],"hex"),r=Buffer.from(t[1],"hex"),s=await Ts(o,n,Ss,{N:ks,r:xs,p:Cs});return s.length!==r.length?!1:il(s,r)}var Sr=class{config;sessions=new Map;failedAttempts=new Map;constructor(e){this.config=e}updateConfig(e){this.config=e}get isEnabled(){return this.config.enabled}get hasPin(){return this.config.pinHash.length>0}async setPin(e){let t=await cl(e);return this.config.pinHash=t,t}async verifyPin(e){return this.hasPin?dl(e,this.config.pinHash):!1}createSession(){let e=ll(),t=this.config.sessionTtlS*1e3,n=Date.now();return this.sessions.set(e,{expiresAt:n+t,lastActivity:n}),e}validateSession(e){let t=this.sessions.get(e);if(!t)return!1;let n=Date.now();if(n>t.expiresAt)return this.sessions.delete(e),!1;if(this.config.lockOnIdle&&this.config.idleTimeoutS>0){let r=this.config.idleTimeoutS*1e3;if(n-t.lastActivity>r)return this.sessions.delete(e),!1}return!0}invalidateSession(e){return this.sessions.delete(e)}touchSession(e){let t=this.sessions.get(e);return t?(t.lastActivity=Date.now(),!0):!1}get activeSessionCount(){return this.sessions.size}getFailedAttempts(e){return this.pruneExpiredAttempts(e),this.failedAttempts.get(e)?.timestamps.length??0}recordFailedAttempt(e){let t=this.failedAttempts.get(e)??{timestamps:[]};t.timestamps.push(Date.now()),this.failedAttempts.set(e,t)}isRateLimited(e){return this.getFailedAttempts(e)>=al}getRateLimitRemainingMs(e){let t=this.failedAttempts.get(e);if(!t||t.timestamps.length===0)return 0;let s=t.timestamps[0]+vs-Date.now();return s>0?s:0}clearFailedAttempts(e){this.failedAttempts.delete(e)}pruneExpiredSessions(){let e=Date.now(),t=0;for(let[n,r]of this.sessions)e>r.expiresAt&&(this.sessions.delete(n),t++);return t}reset(){this.sessions.clear(),this.failedAttempts.clear()}pruneExpiredAttempts(e){let t=this.failedAttempts.get(e);if(!t)return;let n=Date.now()-vs;t.timestamps=t.timestamps.filter(r=>r>n),t.timestamps.length===0&&this.failedAttempts.delete(e)}};function Es(o){let e=ke.extname(o).toLowerCase();return[".png",".jpg",".jpeg",".gif",".webp",".svg"].includes(e)?`image/${e===".svg"?"svg+xml":e.slice(1)}`:e===".pdf"?"application/pdf":e===".json"?"application/json":e===".md"?"text/markdown":e===".js"||e===".mjs"||e===".cjs"?"text/javascript":e===".ts"||e===".tsx"?"text/typescript":e===".jsx"?"text/jsx":e===".html"?"text/html":e===".css"?"text/css":e===".csv"?"text/csv":e===".tsv"?"text/tab-separated-values":[".txt",".log",".yml",".yaml",".xml",".sh",".py",".rb",".java",".go",".rs"].includes(e)?"text/plain":"application/octet-stream"}function Ps(o){return o.startsWith("text/")||o==="application/json"}function bl(){let o=ze("dashboard");if(!o)return null;let e=ke.join(o,"index.html");return de.existsSync(e)?o:null}function ne(o){return new Promise(e=>{let t="";o.on("data",n=>{t+=n.toString(),t.length>2e6&&o.destroy()}),o.on("end",()=>{try{e(t?JSON.parse(t):{})}catch{e({})}}),o.on("error",()=>e({}))})}function y(o,e,t){o.statusCode=e,o.setHeader("Content-Type","application/json; charset=utf-8"),o.end(JSON.stringify(t))}function vl(o){if(!o.includes(":"))return{channel:null,chatId:null};let[e,t]=o.split(/:(.*)/s,2);return{channel:e||null,chatId:t||null}}function Cr(o){return o.map(e=>{let t={...e};return e.reasoning_content&&!e.thinkingContent&&(t.thinkingContent=e.reasoning_content),t})}function Tr(o,e=96){let t=typeof o=="string"?o.trim().replace(/\s+/g," "):"";return t?t.length>e?`${t.slice(0,Math.max(0,e-1)).trimEnd()}\u2026`:t:null}function wl(o){let e=Cr(o),t=[...e].reverse().find(n=>Tr(n.content));return{messageCount:e.length,lastMessagePreview:t?Tr(t.content,120):null,lastMessageRole:t&&typeof t.role=="string"?t.role:null}}function Sl(o){return o.trim().toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"")}function io(o){return typeof o=="string"?o.trim():""}function Ds(o){return io(o?.metadata?.displayName)||null}function kl(o){let e=new Set;for(let n of o){let r=Ds(n)?.match(/^#space\s+(\d+)$/i);if(!r)continue;let s=Number(r[1]);Number.isInteger(s)&&s>0&&e.add(s)}let t=1;for(;e.has(t);)t+=1;return`#Space ${t}`}function xl(o,e){let t=Sl(e)||"dashboard",n=t,r=2;for(;o.has(`web:${n}`);)n=`${t}-${r}`,r+=1;return`web:${n}`}function so(o){let e=new Set,t=[];for(let n of[...Cr(o)].reverse()){if(n.role!=="user"||typeof n.content!="string")continue;let r=n.content.trim().replace(/\s+/g," ");if(!(!r||r.startsWith("/")||e.has(r))&&(e.add(r),t.push({id:`suggestion-${t.length+1}`,text:r,label:Tr(r,56)??r}),t.length>=3))break}return t}function xr(o,e,t,n){let{channel:r,chatId:s}=vl(o.key),i=wl(n?.messages??[]),a=Number(n?.metadata?.pinnedOrder),l=Number(n?.metadata?.recentOrder);return{key:o.key,channel:r,chatId:s,displayName:Ds(n),createdAt:o.created_at,updatedAt:o.updated_at,isCurrent:o.key===e,isDefault:o.key===e,isRunning:t,messageCount:i.messageCount,lastMessagePreview:i.lastMessagePreview,lastMessageRole:i.lastMessageRole,isPinned:n?.metadata?.isPinned===!0,pinnedOrder:Number.isFinite(a)?a:null,recentOrder:Number.isFinite(l)?l:null}}function Is(o,e){return o.listSessions().map(t=>o.getOrCreate(String(t.key??""))).filter(t=>t.key&&t.key!==e&&t.metadata?.isPinned===!0).sort((t,n)=>{let r=Number.isFinite(Number(t.metadata?.pinnedOrder))?Number(t.metadata?.pinnedOrder):Number.POSITIVE_INFINITY,s=Number.isFinite(Number(n.metadata?.pinnedOrder))?Number(n.metadata?.pinnedOrder):Number.POSITIVE_INFINITY;if(r!==s)return r-s;let i=Date.parse(String(t.updatedAt??"")),a=Date.parse(String(n.updatedAt??"")),l=Number.isFinite(i)?i:0,c=Number.isFinite(a)?a:0;return l!==c?c-l:t.key.localeCompare(n.key)})}function Ms(o,e){e.forEach((t,n)=>{t.metadata={...t.metadata,isPinned:!0,pinnedOrder:n},o.save(t)})}function _s(o,e){return o.listSessions().map(t=>o.getOrCreate(String(t.key??""))).filter(t=>t.key&&t.key!==e&&t.metadata?.isPinned!==!0).sort((t,n)=>{let r=Number.isFinite(Number(t.metadata?.recentOrder))?Number(t.metadata?.recentOrder):Number.POSITIVE_INFINITY,s=Number.isFinite(Number(n.metadata?.recentOrder))?Number(n.metadata?.recentOrder):Number.POSITIVE_INFINITY;if(r!==s)return r-s;let i=Date.parse(String(t.updatedAt??"")),a=Date.parse(String(n.updatedAt??"")),l=Number.isFinite(i)?i:0,c=Number.isFinite(a)?a:0;return l!==c?c-l:t.key.localeCompare(n.key)})}function Os(o,e){e.forEach((t,n)=>{t.metadata={...t.metadata,recentOrder:n},o.save(t)})}function Cl(o){return o.endsWith(".html")?"text/html; charset=utf-8":o.endsWith(".js")?"text/javascript; charset=utf-8":o.endsWith(".css")?"text/css; charset=utf-8":o.endsWith(".json")?"application/json; charset=utf-8":o.endsWith(".svg")?"image/svg+xml":"application/octet-stream"}function et(o){return!!o&&typeof o=="object"&&!Array.isArray(o)}function ao(o){return!o||o.length<=4?"***":`***${o.slice(-4)}`}function Tl(o){return o==="127.0.0.1"||o==="::1"||o==="::ffff:127.0.0.1"}function $s(o,e,t){return Tl(o.socket.remoteAddress)?!0:(y(e,403,{error:t}),!1)}function mn(o){return o.map(e=>String(e)).join(".")}function lo(o,e){let t=o;for(let n of e){if(typeof n=="number"){if(!Array.isArray(t))return;t=t[n];continue}if(!et(t))return;t=t[n]}return t}function xe(o,e,t){if(e.length===0)return;let n=o;for(let s=0;s<e.length-1;s+=1){let i=e[s];if(typeof i=="number"){if(!Array.isArray(n))throw new Error(`Expected array while writing ${mn(e)}`);let c=n[i],u=e[s+1];c===void 0&&(n[i]=typeof u=="number"?[]:{}),n=n[i];continue}if(!et(n))throw new Error(`Expected object while writing ${mn(e)}`);let a=n[i],l=e[s+1];a===void 0&&(n[i]=typeof l=="number"?[]:{}),n=n[i]}let r=e[e.length-1];if(typeof r=="number"){if(!Array.isArray(n))throw new Error(`Expected array while writing ${mn(e)}`);n[r]=t;return}if(!et(n))throw new Error(`Expected object while writing ${mn(e)}`);n[r]=t}function qe(o,e){let t=o.length>0;return{configured:t,preview:t?e?.preview??ao(o):null}}function Rl(o){let e=structuredClone(o),t={};for(let[n,r]of Object.entries(o.providers??{}))xe(t,["providers",n,"apiKey"],qe(r?.apiKey??"")),e.providers[n]&&(e.providers[n].apiKey="");e.customLlmProviders.forEach((n,r)=>{xe(t,["customLlmProviders",r,"apiKey"],qe(n?.apiKey??"")),e.customLlmProviders[r]&&(e.customLlmProviders[r].apiKey="")}),xe(t,["channels","telegram","token"],qe(o.channels.telegram.token)),xe(t,["channels","discord","token"],qe(o.channels.discord.token)),e.channels.telegram.token="",e.channels.discord.token="",xe(t,["security","auth","pinHash"],qe(o.security.auth.pinHash,{preview:o.security.auth.pinHash?"[set]":null})),e.security.auth.pinHash="",xe(t,["tools","browserRelay","authToken"],qe(o.tools.browserRelay.authToken)),e.tools.browserRelay.authToken="",xe(t,["tools","web","search","apiKey"],qe(o.tools.web.search.apiKey)),e.tools.web.search.apiKey="";for(let[n,r]of Object.entries(o.tools.mcpServers??{})){for(let[s,i]of Object.entries(r.env??{}))xe(t,["tools","mcpServers",n,"env",s],qe(i)),e.tools.mcpServers[n]?.env?.[s]!==void 0&&(e.tools.mcpServers[n].env[s]="");for(let[s,i]of Object.entries(r.headers??{}))xe(t,["tools","mcpServers",n,"headers",s],qe(i)),e.tools.mcpServers[n]?.headers?.[s]!==void 0&&(e.tools.mcpServers[n].headers[s]="")}return{config:e,secretState:t}}function Ns(o,e,t,n){let r=lo(o,e),s=mn(e);if(r==null){if(!t&&!n)return null;if(!t&&n)return{action:"set",value:n};throw new Error(`Missing secretChanges action for '${s}'.`)}if(!et(r))throw new Error(`Invalid secretChanges entry for '${s}'.`);let i=r.action;if(i!=="keep"&&i!=="clear"&&i!=="set")throw new Error(`Invalid secretChanges action for '${s}'.`);if(i==="set"){let a=typeof r.value=="string"?r.value:n;if(!a)throw new Error(`secretChanges '${s}' must include a non-empty value when action is 'set'.`);return{action:i,value:a}}return{action:i}}function vt(o,e,t,n){let r=String(lo(e,n)??""),s=String(lo(o,n)??""),i=Ns(t,n,r,s);if(i){if(i.action==="keep"){xe(o,n,r);return}if(i.action==="clear"){xe(o,n,"");return}xe(o,n,i.value??s)}}function Ls(o){return et(o)&&Object.values(o).every(e=>typeof e=="string")}function Al(o){try{let e=new URL(o);return["http:","https:","ws:","wss:"].includes(e.protocol)}catch{return!1}}function El(o){if(!et(o))return["tools.mcpServers must be an object."];let e=[],t=new Set;for(let[n,r]of Object.entries(o)){let s=n.trim(),i=s||"(unnamed server)";if(!s){e.push("MCP server names cannot be empty.");continue}let a=s.toLowerCase();if(t.has(a)){e.push(`MCP server '${s}' is duplicated.`);continue}if(t.add(a),!et(r)){e.push(`MCP server '${i}' must be an object.`);continue}let l=typeof r.command=="string"?r.command.trim():"",c=typeof r.url=="string"?r.url.trim():"",u=Number(r.toolTimeout);!l&&!c&&e.push(`MCP server '${i}' requires either a command or a URL.`),l&&c&&e.push(`MCP server '${i}' must use either a command or a URL, not both.`),c&&!Al(c)&&e.push(`MCP server '${i}' must use an http(s) or ws(s) URL.`),r.args!==void 0&&(!Array.isArray(r.args)||r.args.some(g=>typeof g!="string"))&&e.push(`MCP server '${i}' args must be an array of strings.`),r.env!==void 0&&!Ls(r.env)&&e.push(`MCP server '${i}' env must be a string map.`),r.headers!==void 0&&!Ls(r.headers)&&e.push(`MCP server '${i}' headers must be a string map.`),(!Number.isFinite(u)||u<=0)&&e.push(`MCP server '${i}' must have a positive tool timeout.`)}return e}function Pl(o){if(Array.isArray(o.customAcpProviders))return o;let e=M();return{...o,customAcpProviders:structuredClone(e.customAcpProviders)}}var Il=new Set(["/api/auth/login","/api/auth/status","/api/auth/set-pin","/api/browser-relay/config"]),Ml={GET:"\x1B[32m",POST:"\x1B[34m",PUT:"\x1B[33m",DELETE:"\x1B[31m"};function js(o){let e=bl(),t=o.port??o.config.gateway.port??6767,n=o.skillsService??ys(),r=null,s=o.inboxService??null,i=!1;o.config.gateway.dashboard?.enabled!==!1&&!e&&(console.log("[gateway] Dashboard assets not found. The gateway is running in API-only mode."),console.log("[gateway] Install the full package or run `npm run build:dashboard` to enable the web UI."));let l=new Sr(o.config.security.auth),c=()=>(r||(r=new vr(o.workspacePath??process.cwd(),o.dataDir)),r),u=()=>(s||(s=new Bt(o.workspacePath??process.cwd(),o.dataDir)),s),g=v=>typeof o.sessionManager.listSessions!="function"?v===o.sessionKey:o.sessionManager.listSessions().some(b=>String(b.key??"")===v)||v===o.sessionKey,h=(v,d)=>{let b=v||o.sessionKey;return g(b)?{sessionKey:b}:{error:{error:d,session:b}}},T=yl(async(v,d)=>{let b=v.method||"GET",$=new URL(v.url||"/",`http://${v.headers.host||"localhost"}`),k=$.pathname;d.setHeader("X-Content-Type-Options","nosniff"),d.setHeader("X-Frame-Options","DENY"),d.setHeader("Referrer-Policy","no-referrer"),d.setHeader("Content-Security-Policy","default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self' data:; connect-src 'self' ws: wss:;");let U=Ml[b]??"\x1B[0m";if(console.log(`[gateway] ${U}${b}\x1B[0m ${k}`),l.isEnabled&&k.startsWith("/api/")&&!Il.has(k)){let p=v.headers["x-auth-token"];if(!p||typeof p!="string"||!l.validateSession(p))return y(d,401,{error:"Authentication required"});l.touchSession(p)}if(!l.isEnabled&&k==="/api/config"&&(b==="GET"||b==="PUT")&&!$s(v,d,"Config access is only available from localhost when dashboard auth is disabled."))return;if(b==="POST"&&k==="/api/auth/login"){let p=await ne(v),m=String(p.pin??"");if(!m)return y(d,400,{error:"PIN is required"});let f=v.socket.remoteAddress??"unknown";if(l.isRateLimited(f)){let E=l.getRateLimitRemainingMs(f);return y(d,429,{error:"Too many failed attempts. Please try again later.",retryAfterMs:E})}if(!l.hasPin)return y(d,400,{error:"No PIN has been set. Use /api/auth/set-pin to set one."});if(!await l.verifyPin(m))return l.recordFailedAttempt(f),y(d,401,{error:"Invalid PIN"});l.clearFailedAttempts(f);let x=l.createSession();return y(d,200,{token:x})}if(b==="GET"&&k==="/api/auth/status")return y(d,200,{authenticated:!1,authEnabled:l.isEnabled,hasPin:l.hasPin});if(b==="POST"&&k==="/api/auth/logout"){let p=v.headers["x-auth-token"];return!p||typeof p!="string"?y(d,200,{ok:!0}):(l.invalidateSession(p),y(d,200,{ok:!0}))}if(b==="POST"&&k==="/api/auth/set-pin"){let p=await ne(v),m=String(p.newPin??""),f=p.currentPin!==void 0?String(p.currentPin):void 0;if(!m)return y(d,400,{error:"newPin is required"});if(m.length!==6)return y(d,400,{error:"PIN must be 6 digits"});if(!/^\d+$/.test(m))return y(d,400,{error:"PIN must contain only digits"});if(l.hasPin){let C=v.headers["x-auth-token"];if(!(C&&typeof C=="string"&&l.validateSession(C))){let _=v.socket.remoteAddress??"unknown";if(l.isRateLimited(_)){let V=l.getRateLimitRemainingMs(_);return y(d,429,{error:"Too many failed attempts. Please try again later.",retryAfterMs:V})}if(!f)return y(d,401,{error:"Current PIN is required to change PIN"});if(!await l.verifyPin(f))return l.recordFailedAttempt(_),y(d,401,{error:"Current PIN is incorrect"});l.clearFailedAttempts(_)}}else{let C=process.env.EVERCLAW_BOOTSTRAP_PIN;if(C&&String(p.bootstrapSecret??"")!==C)return y(d,403,{error:"Bootstrap secret required for first-time PIN setup. Set EVERCLAW_BOOTSTRAP_PIN env var and provide it in the request."})}let w=!l.hasPin,x=await l.setPin(m);w||l.reset();let E=M();return E.security?.auth&&(E.security.auth.pinHash=x,oe(E)),y(d,200,{ok:!0,message:w?"PIN set successfully":"PIN changed successfully"})}let L=()=>y(d,503,{error:"Gateway is shutting down. Please try again later."}),N=k.match(/^\/api\/cron\/jobs\/([^/]+)$/),z=k.match(/^\/api\/cron\/jobs\/([^/]+)\/enable$/),F=k.match(/^\/api\/cron\/jobs\/([^/]+)\/run$/),ae=k.match(/^\/api\/inbox-deliveries\/([^/]+)$/),J=k.match(/^\/api\/inbox-deliveries\/([^/]+)\/clear$/),Z=k.match(/^\/api\/sessions\/([^/]+)$/),A=k.match(/^\/api\/session-files\/([^/]+)$/);if(i&&(b==="POST"&&k==="/api/chat"||b==="POST"&&k==="/api/sessions"||b==="PUT"&&!!Z||b==="PUT"&&k==="/api/config"||b==="POST"&&k==="/api/skills/install"||b==="POST"&&!!J||b==="POST"&&k==="/api/session-files"||b==="POST"&&k==="/api/cron/jobs"||b==="DELETE"&&!!A||b==="DELETE"&&!!N||b==="POST"&&!!z||b==="POST"&&!!F))return L();if(b==="GET"&&k==="/api/status"){let p=M(),m=o.agent.getRuntimeState(),f=o.cron.status(),w=ps({config:p,runtime:m,cron:f}),x=structuredClone(p.channels);x.telegram?.token&&(x.telegram.token=ao(x.telegram.token)),x.discord?.token&&(x.discord.token=ao(x.discord.token));let E=o.channelManager?.getStatus()??{};return y(d,200,{provider:p.agents.defaults.provider,model:p.agents.defaults.model,cron:f,channels:x,channelStatus:E,gateway:{...p.gateway,port:t},runtime:m,isolation:w,shutdown:{active:i||!m.acceptingWork,rejectingMutations:i}})}if(b==="GET"&&k==="/api/chrome-session/status"){let p=M(),m=$.searchParams.get("port"),f=m?parseInt(m,10):p.tools.chromeSession?.debugPort??9222,w=p.tools.chromeSession?.minChromeVersion??136,x=await It(f);if(!x)return y(d,200,{available:!1,reason:"Chrome remote debugging not detected",hint:"Enable remote debugging in Chrome at chrome://inspect/#remote-debugging or use the Launch Chrome button.",debugPort:f});if(x.pendingApproval)return y(d,200,{available:!1,pendingApproval:!0,reason:"Chrome is running but remote debugging has not been approved yet",hint:"Open chrome://inspect/#remote-debugging in Chrome and click 'Allow' to approve the remote debugging connection.",fixCommand:`open -a 'Google Chrome' --args --remote-debugging-port=${x.port} --user-data-dir=/tmp/chrome-debug-profile`,port:x.port,debugPort:f});let{port:E,versionInfo:C}=x,R=C.Browser.match(/(\w+)\/(\d+)/),_=R?.[1]??"Chrome",P=R?parseInt(R[2],10):0;return P>0&&P<w?y(d,200,{available:!1,reason:`Chrome version ${P} is below minimum required version ${w}`,hint:`Update Chrome to version ${w} or higher`,version:C.Browser,port:E,browser:_,debugPort:f}):y(d,200,{available:!0,version:C.Browser,remoteDebugging:!0,port:E,browser:_,debugPort:f})}if(b==="POST"&&k==="/api/chrome-session/launch"){let p=await ne(v),m=M(),f=p.port??m.tools.chromeSession?.debugPort??9222,w=await It(f);if(w&&!w.pendingApproval){let P=w.versionInfo.Browser.match(/(\w+)\/(\d+)/);return y(d,200,{ok:!0,launched:!1,alreadyRunning:!0,port:w.port,version:w.versionInfo.Browser,browser:P?.[1]??"Chrome",message:`Chrome remote debugging is already active on port ${w.port}. No need to launch.`})}if(w?.pendingApproval)return y(d,200,{ok:!1,launched:!1,pendingApproval:!0,port:w.port,message:"Chrome is running on this port but remote debugging has not been approved yet. Open chrome://inspect/#remote-debugging in Chrome and click 'Allow'."});let x="/tmp/chrome-debug-profile",E=hl(x,"DevToolsActivePort");try{fl(E)}catch{}let C=process.platform,R,_=[`--remote-debugging-port=${f}`,`--user-data-dir=${x}`];if(C==="darwin"){let P=["/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",`${process.env.HOME}/Applications/Google Chrome.app/Contents/MacOS/Google Chrome`,"/Applications/Chromium.app/Contents/MacOS/Chromium","/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary","/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge","/Applications/Brave Browser.app/Contents/MacOS/Brave Browser"],V=P.find(D=>bt(D));if(!V)return y(d,500,{ok:!1,error:"No supported Chromium-based browser found",searched:P,hint:"Install Google Chrome or specify the path manually."});R=V}else if(C==="win32"){R="cmd.exe";let P=process.env.ProgramFiles??"C:\\Program Files",V=process.env.LOCALAPPDATA??"C:\\Users\\Default\\AppData\\Local",D=[`${P}\\Google\\Chrome\\Application\\chrome.exe`,`${V}\\Google\\Chrome\\Application\\chrome.exe`,`${P}\\Microsoft\\Edge\\Application\\msedge.exe`,`${V}\\Microsoft\\Edge\\Application\\msedge.exe`],me=D.find(Re=>bt(Re));if(!me)return y(d,500,{ok:!1,error:"No supported Chromium-based browser found",searched:D,hint:"Install Google Chrome or Microsoft Edge."});_=["/c","start","",me,`--remote-debugging-port=${f}`]}else{let P=["/usr/bin/google-chrome","/usr/bin/google-chrome-stable","/usr/bin/chromium","/usr/bin/chromium-browser","/snap/bin/chromium"],V=P.find(D=>bt(D));if(!V)return y(d,500,{ok:!1,error:"No supported Chromium-based browser found",searched:P,hint:"Install Google Chrome or Chromium."});R=V}try{let P=As(R,_,{detached:!0,stdio:"ignore"}),V=await Promise.race([new Promise(Re=>P.once("error",Re)),new Promise(Re=>setTimeout(()=>Re(null),500))]);if(V)return y(d,500,{ok:!1,error:V.message,chromePath:R,hint:"Could not launch Chrome. Please start Chrome manually with --remote-debugging-port=9222"});P.unref();let D;for(let Re=0;Re<5&&(await new Promise(st=>setTimeout(st,1e3)),D=await It(f),!D);Re++);if(!D)return y(d,200,{ok:!1,launched:!0,port:f,chromePath:R,message:"Chrome was launched but CDP is not fully active. You may need to click 'Allow' in Chrome's remote debugging prompt, or try closing all existing Chrome windows first, then retry."});if(D.pendingApproval)return y(d,200,{ok:!1,launched:!0,pendingApproval:!0,port:D.port,chromePath:R,message:"Chrome was launched but remote debugging has not been approved yet. Open chrome://inspect/#remote-debugging in Chrome and click 'Allow' to enable agent control."});let me=D.versionInfo.Browser.match(/(\w+)\/(\d+)/);return y(d,200,{ok:!0,launched:!0,port:D.port,chromePath:R,version:D.versionInfo.Browser,browser:me?.[1]??"Chrome",message:`Chrome launched successfully with remote debugging on port ${D.port}`})}catch(P){return y(d,500,{ok:!1,error:P instanceof Error?P.message:String(P),chromePath:R,hint:"Could not launch Chrome. Please start Chrome manually with --remote-debugging-port=9222"})}}if(b==="GET"&&k==="/api/browser-relay/status"){let m=M().tools.browserRelay;if(!m.enabled)return y(d,200,{enabled:!1,connected:!1,attachedTabs:[],extensionPath:m.extensionPath});if(o.browserRelay){let f=o.browserRelay.getStatus();return y(d,200,{enabled:!0,connected:f.connected,attachedTabs:f.attachedTabs,lastPing:f.lastPing,extensionPath:m.extensionPath})}return y(d,200,{enabled:m.enabled,connected:!1,attachedTabs:[],extensionPath:m.extensionPath})}if(b==="GET"&&k==="/api/browser-relay/config"){if(!$s(v,d,"Browser Relay bootstrap is only available from localhost."))return;let p=M(),m=p.tools.browserRelay;return y(d,200,{enabled:m.enabled,port:p.gateway.port,token:m.enabled&&m.authToken||""})}if(b==="POST"&&k==="/api/browser-relay/launch"){let p=await ne(v),m=M(),f=p.extensionPath??m.tools.browserRelay.extensionPath;if(!f)return y(d,400,{ok:!1,error:"No extension path configured",hint:"Set the extension path in Settings > Tools > Browser Relay"});let w=process.platform,x,E=[`--load-extension=${f}`,"--no-first-run","--no-default-browser-check"];if(w==="darwin")x=["/Applications/Google Chrome.app/Contents/MacOS/Google Chrome","/Applications/Chromium.app/Contents/MacOS/Chromium"].find(bt)??"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome";else if(w==="win32"){let C=process.env.ProgramFiles??"C:\\Program Files",R=process.env["ProgramFiles(x86)"]??"C:\\Program Files (x86)";x=[`${C}\\Google\\Chrome\\Application\\chrome.exe`,`${R}\\Google\\Chrome\\Application\\chrome.exe`].find(bt)??`${C}\\Google\\Chrome\\Application\\chrome.exe`}else x="google-chrome";try{return As(x,E,{detached:!0,stdio:"ignore"}).unref(),y(d,200,{ok:!0,launched:!0,extensionPath:f,message:`Chrome launched with extension from ${f}`})}catch(C){return y(d,500,{ok:!1,error:C instanceof Error?C.message:String(C),hint:"Could not launch Chrome. Please load the extension manually via chrome://extensions"})}}let I=k.match(/^\/api\/automations(?:\/([^/]+))?(\/run)?$/),j=X(o.config.agents.defaults.workspace);if(b==="GET"&&k==="/api/automations"){let p=Ot(j);return y(d,200,p)}if(b==="GET"&&I&&I[1]&&!I[2]){let p=I[1],m=Se(j,p);return m?y(d,200,m):y(d,404,{error:"Automation not found"})}if(b==="POST"&&k==="/api/automations"){let p=await ne(v);try{let m={name:String(p.name??"Untitled"),description:String(p.description??""),steps:p.steps||[],tags:p.tags||[],source:p.source||"manual"};p.toolType!==void 0&&(m.toolType=p.toolType),p.variables!==void 0&&(m.variables=p.variables);let f=Vn(j,m);return y(d,201,f)}catch(m){return y(d,400,{error:String(m)})}}if(b==="PUT"&&I&&I[1]&&!I[2]){let p=I[1],m=await ne(v),f={};m.name!==void 0&&(f.name=String(m.name)),m.description!==void 0&&(f.description=String(m.description)),m.enabled!==void 0&&(f.enabled=!!m.enabled),m.steps!==void 0&&(f.steps=m.steps),m.tags!==void 0&&(f.tags=m.tags),m.toolType!==void 0&&(f.toolType=m.toolType),m.variables!==void 0&&(f.variables=m.variables);let w=Xn(j,p,f);return w?y(d,200,w):y(d,404,{error:"Automation not found"})}if(b==="DELETE"&&I&&I[1]){let p=I[1];return $t(j,p)?y(d,200,{ok:!0}):y(d,404,{error:"Automation not found"})}if(b==="POST"&&I&&I[1]&&I[2]==="/run"){let p=I[1],m=Se(j,p);return m?m.enabled?(o.agent.tools.execute("automation",{command:"run",id:p}).then(f=>{console.log(`[automation] Execution of '${m.name}' finished`,{logs:f.kind==="ok"?f.content:f})}).catch(f=>{console.error(`[automation] Execution of '${m.name}' failed`,{err:f})}),y(d,200,{ok:!0,message:`Automation '${m.name}' execution started in background.`})):y(d,400,{error:"Automation is disabled"}):y(d,404,{error:"Automation not found"})}if(b==="GET"&&k==="/api/history"){let p=String($.searchParams.get("session")??"").trim(),m=h(p,"Session history not found.");if(m.error)return y(d,404,m.error);let f=m.sessionKey,w=o.sessionManager.getOrCreate(f);return y(d,200,{session:f,messages:Cr(w.messages)})}if(b==="GET"&&k==="/api/sessions"){let p=o.agent.getRuntimeState(),m=new Set((p.sessions||[]).filter(x=>x.running||x.queued>0).map(x=>x.key)),f=o.sessionManager.getOrCreate(o.sessionKey),w=o.sessionManager.listSessions().filter(x=>String(x.key??"")!==o.sessionKey).map(x=>{let E=String(x.key??"");return xr({key:E,created_at:String(x.created_at??f.createdAt),updated_at:String(x.updated_at??f.updatedAt)},o.sessionKey,m.has(E),o.sessionManager.getOrCreate(E))});return y(d,200,{currentSession:o.sessionKey,sessions:[xr({key:f.key,created_at:f.createdAt,updated_at:f.updatedAt},o.sessionKey,m.has(f.key),f),...w]})}if(b==="GET"&&k==="/api/files/preview"){let p=String($.searchParams.get("path")??"").trim(),m=parseInt($.searchParams.get("maxLines")??"100",10),f=o.workspacePath??process.cwd();if(!p)return y(d,400,{error:"path required"});try{je(p,f)}catch{return y(d,403,{error:"Access denied: path outside workspace"})}if(!bt(p))return y(d,404,{error:"file not found"});try{let w=de.statSync(p);if(w.isDirectory())return y(d,400,{error:"path is a directory"});let x=Es(p),E=de.readFileSync(p),C=null,R=!1;if(Ps(x)){let D=E.toString("utf-8").split(`
300
+ Signal: ${o.signal}`:"";return`${e||"Skill install failed."}${t}${n}`.trim()}$e();le();import{scrypt as sl,randomBytes as ws,timingSafeEqual as il}from"node:crypto";var Ss=64,ks=16384,xs=8,Cs=1,al=5,vs=300*1e3;function ll(){let o=ws(16);o[6]=o[6]&15|64,o[8]=o[8]&63|128;let e=o.toString("hex");return`${e.slice(0,8)}-${e.slice(8,12)}-${e.slice(12,16)}-${e.slice(16,20)}-${e.slice(20)}`}function Ts(o,e,t,n){let r=n??{};return new Promise((s,i)=>{sl(o,e,t,r,(a,l)=>{a?i(a):s(l)})})}async function cl(o,e){let t=e??ws(16),n=await Ts(o,t,Ss,{N:ks,r:xs,p:Cs});return`${t.toString("hex")}:${n.toString("hex")}`}async function dl(o,e){let t=e.split(":");if(t.length!==2)return!1;let n=Buffer.from(t[0],"hex"),r=Buffer.from(t[1],"hex"),s=await Ts(o,n,Ss,{N:ks,r:xs,p:Cs});return s.length!==r.length?!1:il(s,r)}var Sr=class{config;sessions=new Map;failedAttempts=new Map;constructor(e){this.config=e}updateConfig(e){this.config=e}get isEnabled(){return this.config.enabled}get hasPin(){return this.config.pinHash.length>0}async setPin(e){let t=await cl(e);return this.config.pinHash=t,t}async verifyPin(e){return this.hasPin?dl(e,this.config.pinHash):!1}createSession(){let e=ll(),t=this.config.sessionTtlS*1e3,n=Date.now();return this.sessions.set(e,{expiresAt:n+t,lastActivity:n}),e}validateSession(e){let t=this.sessions.get(e);if(!t)return!1;let n=Date.now();if(n>t.expiresAt)return this.sessions.delete(e),!1;if(this.config.lockOnIdle&&this.config.idleTimeoutS>0){let r=this.config.idleTimeoutS*1e3;if(n-t.lastActivity>r)return this.sessions.delete(e),!1}return!0}invalidateSession(e){return this.sessions.delete(e)}touchSession(e){let t=this.sessions.get(e);return t?(t.lastActivity=Date.now(),!0):!1}get activeSessionCount(){return this.sessions.size}getFailedAttempts(e){return this.pruneExpiredAttempts(e),this.failedAttempts.get(e)?.timestamps.length??0}recordFailedAttempt(e){let t=this.failedAttempts.get(e)??{timestamps:[]};t.timestamps.push(Date.now()),this.failedAttempts.set(e,t)}isRateLimited(e){return this.getFailedAttempts(e)>=al}getRateLimitRemainingMs(e){let t=this.failedAttempts.get(e);if(!t||t.timestamps.length===0)return 0;let s=t.timestamps[0]+vs-Date.now();return s>0?s:0}clearFailedAttempts(e){this.failedAttempts.delete(e)}pruneExpiredSessions(){let e=Date.now(),t=0;for(let[n,r]of this.sessions)e>r.expiresAt&&(this.sessions.delete(n),t++);return t}reset(){this.sessions.clear(),this.failedAttempts.clear()}pruneExpiredAttempts(e){let t=this.failedAttempts.get(e);if(!t)return;let n=Date.now()-vs;t.timestamps=t.timestamps.filter(r=>r>n),t.timestamps.length===0&&this.failedAttempts.delete(e)}};function Es(o){let e=ke.extname(o).toLowerCase();return[".png",".jpg",".jpeg",".gif",".webp",".svg"].includes(e)?`image/${e===".svg"?"svg+xml":e.slice(1)}`:e===".pdf"?"application/pdf":e===".json"?"application/json":e===".md"?"text/markdown":e===".js"||e===".mjs"||e===".cjs"?"text/javascript":e===".ts"||e===".tsx"?"text/typescript":e===".jsx"?"text/jsx":e===".html"?"text/html":e===".css"?"text/css":e===".csv"?"text/csv":e===".tsv"?"text/tab-separated-values":[".txt",".log",".yml",".yaml",".xml",".sh",".py",".rb",".java",".go",".rs"].includes(e)?"text/plain":"application/octet-stream"}function Ps(o){return o.startsWith("text/")||o==="application/json"}function bl(){let o=ze("dashboard");if(!o)return null;let e=ke.join(o,"index.html");return de.existsSync(e)?o:null}function ne(o){return new Promise(e=>{let t="";o.on("data",n=>{t+=n.toString(),t.length>2e6&&o.destroy()}),o.on("end",()=>{try{e(t?JSON.parse(t):{})}catch{e({})}}),o.on("error",()=>e({}))})}function y(o,e,t){o.statusCode=e,o.setHeader("Content-Type","application/json; charset=utf-8"),o.end(JSON.stringify(t))}function vl(o){if(!o.includes(":"))return{channel:null,chatId:null};let[e,t]=o.split(/:(.*)/s,2);return{channel:e||null,chatId:t||null}}function Cr(o){return o.map(e=>{let t={...e};return e.reasoning_content&&!e.thinkingContent&&(t.thinkingContent=e.reasoning_content),t})}function Tr(o,e=96){let t=typeof o=="string"?o.trim().replace(/\s+/g," "):"";return t?t.length>e?`${t.slice(0,Math.max(0,e-1)).trimEnd()}\u2026`:t:null}function wl(o){let e=Cr(o),t=[...e].reverse().find(n=>Tr(n.content));return{messageCount:e.length,lastMessagePreview:t?Tr(t.content,120):null,lastMessageRole:t&&typeof t.role=="string"?t.role:null}}function Sl(o){return o.trim().toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"")}function io(o){return typeof o=="string"?o.trim():""}function Ds(o){return io(o?.metadata?.displayName)||null}function kl(o){let e=new Set;for(let n of o){let r=Ds(n)?.match(/^#space\s+(\d+)$/i);if(!r)continue;let s=Number(r[1]);Number.isInteger(s)&&s>0&&e.add(s)}let t=1;for(;e.has(t);)t+=1;return`#Space ${t}`}function xl(o,e){let t=Sl(e)||"dashboard",n=t,r=2;for(;o.has(`web:${n}`);)n=`${t}-${r}`,r+=1;return`web:${n}`}function so(o){let e=new Set,t=[];for(let n of[...Cr(o)].reverse()){if(n.role!=="user"||typeof n.content!="string")continue;let r=n.content.trim().replace(/\s+/g," ");if(!(!r||r.startsWith("/")||e.has(r))&&(e.add(r),t.push({id:`suggestion-${t.length+1}`,text:r,label:Tr(r,56)??r}),t.length>=3))break}return t}function xr(o,e,t,n){let{channel:r,chatId:s}=vl(o.key),i=wl(n?.messages??[]),a=Number(n?.metadata?.pinnedOrder),l=Number(n?.metadata?.recentOrder);return{key:o.key,channel:r,chatId:s,displayName:Ds(n),createdAt:o.created_at,updatedAt:o.updated_at,isCurrent:o.key===e,isDefault:o.key===e,isRunning:t,messageCount:i.messageCount,lastMessagePreview:i.lastMessagePreview,lastMessageRole:i.lastMessageRole,isPinned:n?.metadata?.isPinned===!0,pinnedOrder:Number.isFinite(a)?a:null,recentOrder:Number.isFinite(l)?l:null}}function Is(o,e){return o.listSessions().map(t=>o.getOrCreate(String(t.key??""))).filter(t=>t.key&&t.key!==e&&t.metadata?.isPinned===!0).sort((t,n)=>{let r=Number.isFinite(Number(t.metadata?.pinnedOrder))?Number(t.metadata?.pinnedOrder):Number.POSITIVE_INFINITY,s=Number.isFinite(Number(n.metadata?.pinnedOrder))?Number(n.metadata?.pinnedOrder):Number.POSITIVE_INFINITY;if(r!==s)return r-s;let i=Date.parse(String(t.updatedAt??"")),a=Date.parse(String(n.updatedAt??"")),l=Number.isFinite(i)?i:0,c=Number.isFinite(a)?a:0;return l!==c?c-l:t.key.localeCompare(n.key)})}function Ms(o,e){e.forEach((t,n)=>{t.metadata={...t.metadata,isPinned:!0,pinnedOrder:n},o.save(t)})}function _s(o,e){return o.listSessions().map(t=>o.getOrCreate(String(t.key??""))).filter(t=>t.key&&t.key!==e&&t.metadata?.isPinned!==!0).sort((t,n)=>{let r=Number.isFinite(Number(t.metadata?.recentOrder))?Number(t.metadata?.recentOrder):Number.POSITIVE_INFINITY,s=Number.isFinite(Number(n.metadata?.recentOrder))?Number(n.metadata?.recentOrder):Number.POSITIVE_INFINITY;if(r!==s)return r-s;let i=Date.parse(String(t.updatedAt??"")),a=Date.parse(String(n.updatedAt??"")),l=Number.isFinite(i)?i:0,c=Number.isFinite(a)?a:0;return l!==c?c-l:t.key.localeCompare(n.key)})}function Os(o,e){e.forEach((t,n)=>{t.metadata={...t.metadata,recentOrder:n},o.save(t)})}function Cl(o){return o.endsWith(".html")?"text/html; charset=utf-8":o.endsWith(".js")?"text/javascript; charset=utf-8":o.endsWith(".css")?"text/css; charset=utf-8":o.endsWith(".json")?"application/json; charset=utf-8":o.endsWith(".svg")?"image/svg+xml":"application/octet-stream"}function et(o){return!!o&&typeof o=="object"&&!Array.isArray(o)}function ao(o){return!o||o.length<=4?"***":`***${o.slice(-4)}`}function Tl(o){return o==="127.0.0.1"||o==="::1"||o==="::ffff:127.0.0.1"}function $s(o,e,t){return Tl(o.socket.remoteAddress)?!0:(y(e,403,{error:t}),!1)}function mn(o){return o.map(e=>String(e)).join(".")}function lo(o,e){let t=o;for(let n of e){if(typeof n=="number"){if(!Array.isArray(t))return;t=t[n];continue}if(!et(t))return;t=t[n]}return t}function xe(o,e,t){if(e.length===0)return;let n=o;for(let s=0;s<e.length-1;s+=1){let i=e[s];if(typeof i=="number"){if(!Array.isArray(n))throw new Error(`Expected array while writing ${mn(e)}`);let c=n[i],u=e[s+1];c===void 0&&(n[i]=typeof u=="number"?[]:{}),n=n[i];continue}if(!et(n))throw new Error(`Expected object while writing ${mn(e)}`);let a=n[i],l=e[s+1];a===void 0&&(n[i]=typeof l=="number"?[]:{}),n=n[i]}let r=e[e.length-1];if(typeof r=="number"){if(!Array.isArray(n))throw new Error(`Expected array while writing ${mn(e)}`);n[r]=t;return}if(!et(n))throw new Error(`Expected object while writing ${mn(e)}`);n[r]=t}function qe(o,e){let t=o.length>0;return{configured:t,preview:t?e?.preview??ao(o):null}}function Rl(o){let e=structuredClone(o),t={};for(let[n,r]of Object.entries(o.providers??{}))xe(t,["providers",n,"apiKey"],qe(r?.apiKey??"")),e.providers[n]&&(e.providers[n].apiKey="");e.customLlmProviders.forEach((n,r)=>{xe(t,["customLlmProviders",r,"apiKey"],qe(n?.apiKey??"")),e.customLlmProviders[r]&&(e.customLlmProviders[r].apiKey="")}),xe(t,["channels","telegram","token"],qe(o.channels.telegram.token)),xe(t,["channels","discord","token"],qe(o.channels.discord.token)),e.channels.telegram.token="",e.channels.discord.token="",xe(t,["security","auth","pinHash"],qe(o.security.auth.pinHash,{preview:o.security.auth.pinHash?"[set]":null})),e.security.auth.pinHash="",xe(t,["tools","browserRelay","authToken"],qe(o.tools.browserRelay.authToken)),e.tools.browserRelay.authToken="",xe(t,["tools","web","search","apiKey"],qe(o.tools.web.search.apiKey)),e.tools.web.search.apiKey="";for(let[n,r]of Object.entries(o.tools.mcpServers??{})){for(let[s,i]of Object.entries(r.env??{}))xe(t,["tools","mcpServers",n,"env",s],qe(i)),e.tools.mcpServers[n]?.env?.[s]!==void 0&&(e.tools.mcpServers[n].env[s]="");for(let[s,i]of Object.entries(r.headers??{}))xe(t,["tools","mcpServers",n,"headers",s],qe(i)),e.tools.mcpServers[n]?.headers?.[s]!==void 0&&(e.tools.mcpServers[n].headers[s]="")}return{config:e,secretState:t}}function Ns(o,e,t,n){let r=lo(o,e),s=mn(e);if(r==null){if(!t&&!n)return null;if(!t&&n)return{action:"set",value:n};throw new Error(`Missing secretChanges action for '${s}'.`)}if(!et(r))throw new Error(`Invalid secretChanges entry for '${s}'.`);let i=r.action;if(i!=="keep"&&i!=="clear"&&i!=="set")throw new Error(`Invalid secretChanges action for '${s}'.`);if(i==="set"){let a=typeof r.value=="string"?r.value:n;if(!a)throw new Error(`secretChanges '${s}' must include a non-empty value when action is 'set'.`);return{action:i,value:a}}return{action:i}}function vt(o,e,t,n){let r=String(lo(e,n)??""),s=String(lo(o,n)??""),i=Ns(t,n,r,s);if(i){if(i.action==="keep"){xe(o,n,r);return}if(i.action==="clear"){xe(o,n,"");return}xe(o,n,i.value??s)}}function Ls(o){return et(o)&&Object.values(o).every(e=>typeof e=="string")}function Al(o){try{let e=new URL(o);return["http:","https:","ws:","wss:"].includes(e.protocol)}catch{return!1}}function El(o){if(!et(o))return["tools.mcpServers must be an object."];let e=[],t=new Set;for(let[n,r]of Object.entries(o)){let s=n.trim(),i=s||"(unnamed server)";if(!s){e.push("MCP server names cannot be empty.");continue}let a=s.toLowerCase();if(t.has(a)){e.push(`MCP server '${s}' is duplicated.`);continue}if(t.add(a),!et(r)){e.push(`MCP server '${i}' must be an object.`);continue}let l=typeof r.command=="string"?r.command.trim():"",c=typeof r.url=="string"?r.url.trim():"",u=Number(r.toolTimeout);!l&&!c&&e.push(`MCP server '${i}' requires either a command or a URL.`),l&&c&&e.push(`MCP server '${i}' must use either a command or a URL, not both.`),c&&!Al(c)&&e.push(`MCP server '${i}' must use an http(s) or ws(s) URL.`),r.args!==void 0&&(!Array.isArray(r.args)||r.args.some(g=>typeof g!="string"))&&e.push(`MCP server '${i}' args must be an array of strings.`),r.env!==void 0&&!Ls(r.env)&&e.push(`MCP server '${i}' env must be a string map.`),r.headers!==void 0&&!Ls(r.headers)&&e.push(`MCP server '${i}' headers must be a string map.`),(!Number.isFinite(u)||u<=0)&&e.push(`MCP server '${i}' must have a positive tool timeout.`)}return e}function Pl(o){if(Array.isArray(o.customAcpProviders))return o;let e=M();return{...o,customAcpProviders:structuredClone(e.customAcpProviders)}}var Il=new Set(["/api/auth/login","/api/auth/status","/api/auth/set-pin","/api/browser-relay/config"]),Ml={GET:"\x1B[32m",POST:"\x1B[34m",PUT:"\x1B[33m",DELETE:"\x1B[31m"};function js(o){let e=bl(),t=o.port??o.config.gateway.port??6767,n=o.skillsService??ys(),r=null,s=o.inboxService??null,i=!1;o.config.gateway.dashboard?.enabled!==!1&&!e&&(console.log("[gateway] Dashboard assets not found. The gateway is running in API-only mode."),console.log("[gateway] Install the full package or run `npm run build:dashboard` to enable the web UI."));let l=new Sr(o.config.security.auth),c=()=>(r||(r=new vr(o.workspacePath??process.cwd(),o.dataDir)),r),u=()=>(s||(s=new Bt(o.workspacePath??process.cwd(),o.dataDir)),s),g=v=>typeof o.sessionManager.listSessions!="function"?v===o.sessionKey:o.sessionManager.listSessions().some(b=>String(b.key??"")===v)||v===o.sessionKey,h=(v,d)=>{let b=v||o.sessionKey;return g(b)?{sessionKey:b}:{error:{error:d,session:b}}},T=yl(async(v,d)=>{let b=v.method||"GET",$=new URL(v.url||"/",`http://${v.headers.host||"localhost"}`),k=$.pathname;d.setHeader("X-Content-Type-Options","nosniff"),d.setHeader("X-Frame-Options","DENY"),d.setHeader("Referrer-Policy","no-referrer"),d.setHeader("Content-Security-Policy","default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self' data:; connect-src 'self' ws: wss:;");let U=Ml[b]??"\x1B[0m";if(console.log(`[gateway] ${U}${b}\x1B[0m ${k}`),l.isEnabled&&k.startsWith("/api/")&&!Il.has(k)){let p=v.headers["x-auth-token"];if(!p||typeof p!="string"||!l.validateSession(p))return y(d,401,{error:"Authentication required"});l.touchSession(p)}if(!l.isEnabled&&k==="/api/config"&&(b==="GET"||b==="PUT")&&!$s(v,d,"Config access is only available from localhost when dashboard auth is disabled."))return;if(b==="POST"&&k==="/api/auth/login"){let p=await ne(v),m=String(p.pin??"");if(!m)return y(d,400,{error:"PIN is required"});let f=v.socket.remoteAddress??"unknown";if(l.isRateLimited(f)){let E=l.getRateLimitRemainingMs(f);return y(d,429,{error:"Too many failed attempts. Please try again later.",retryAfterMs:E})}if(!l.hasPin)return y(d,400,{error:"No PIN has been set. Use /api/auth/set-pin to set one."});if(!await l.verifyPin(m))return l.recordFailedAttempt(f),y(d,401,{error:"Invalid PIN"});l.clearFailedAttempts(f);let x=l.createSession();return y(d,200,{token:x})}if(b==="GET"&&k==="/api/auth/status")return y(d,200,{authenticated:!1,authEnabled:l.isEnabled,hasPin:l.hasPin});if(b==="POST"&&k==="/api/auth/logout"){let p=v.headers["x-auth-token"];return!p||typeof p!="string"?y(d,200,{ok:!0}):(l.invalidateSession(p),y(d,200,{ok:!0}))}if(b==="POST"&&k==="/api/auth/set-pin"){let p=await ne(v),m=String(p.newPin??""),f=p.currentPin!==void 0?String(p.currentPin):void 0;if(!m)return y(d,400,{error:"newPin is required"});if(m.length!==6)return y(d,400,{error:"PIN must be 6 digits"});if(!/^\d+$/.test(m))return y(d,400,{error:"PIN must contain only digits"});if(l.hasPin){let C=v.headers["x-auth-token"];if(!(C&&typeof C=="string"&&l.validateSession(C))){let _=v.socket.remoteAddress??"unknown";if(l.isRateLimited(_)){let V=l.getRateLimitRemainingMs(_);return y(d,429,{error:"Too many failed attempts. Please try again later.",retryAfterMs:V})}if(!f)return y(d,401,{error:"Current PIN is required to change PIN"});if(!await l.verifyPin(f))return l.recordFailedAttempt(_),y(d,401,{error:"Current PIN is incorrect"});l.clearFailedAttempts(_)}}else{let C=process.env.EVERCLAW_BOOTSTRAP_PIN;if(C&&String(p.bootstrapSecret??"")!==C)return y(d,403,{error:"Bootstrap secret required for first-time PIN setup. Set EVERCLAW_BOOTSTRAP_PIN env var and provide it in the request."})}let w=!l.hasPin,x=await l.setPin(m);w||l.reset();let E=M();return E.security?.auth&&(E.security.auth.pinHash=x,oe(E)),y(d,200,{ok:!0,message:w?"PIN set successfully":"PIN changed successfully"})}let L=()=>y(d,503,{error:"Gateway is shutting down. Please try again later."}),N=k.match(/^\/api\/cron\/jobs\/([^/]+)$/),z=k.match(/^\/api\/cron\/jobs\/([^/]+)\/enable$/),B=k.match(/^\/api\/cron\/jobs\/([^/]+)\/run$/),ae=k.match(/^\/api\/inbox-deliveries\/([^/]+)$/),J=k.match(/^\/api\/inbox-deliveries\/([^/]+)\/clear$/),Z=k.match(/^\/api\/sessions\/([^/]+)$/),A=k.match(/^\/api\/session-files\/([^/]+)$/);if(i&&(b==="POST"&&k==="/api/chat"||b==="POST"&&k==="/api/sessions"||b==="PUT"&&!!Z||b==="PUT"&&k==="/api/config"||b==="POST"&&k==="/api/skills/install"||b==="POST"&&!!J||b==="POST"&&k==="/api/session-files"||b==="POST"&&k==="/api/cron/jobs"||b==="DELETE"&&!!A||b==="DELETE"&&!!N||b==="POST"&&!!z||b==="POST"&&!!B))return L();if(b==="GET"&&k==="/api/status"){let p=M(),m=o.agent.getRuntimeState(),f=o.cron.status(),w=ps({config:p,runtime:m,cron:f}),x=structuredClone(p.channels);x.telegram?.token&&(x.telegram.token=ao(x.telegram.token)),x.discord?.token&&(x.discord.token=ao(x.discord.token));let E=o.channelManager?.getStatus()??{};return y(d,200,{provider:p.agents.defaults.provider,model:p.agents.defaults.model,cron:f,channels:x,channelStatus:E,gateway:{...p.gateway,port:t},runtime:m,isolation:w,shutdown:{active:i||!m.acceptingWork,rejectingMutations:i}})}if(b==="GET"&&k==="/api/chrome-session/status"){let p=M(),m=$.searchParams.get("port"),f=m?parseInt(m,10):p.tools.chromeSession?.debugPort??9222,w=p.tools.chromeSession?.minChromeVersion??136,x=await It(f);if(!x)return y(d,200,{available:!1,reason:"Chrome remote debugging not detected",hint:"Enable remote debugging in Chrome at chrome://inspect/#remote-debugging or use the Launch Chrome button.",debugPort:f});if(x.pendingApproval)return y(d,200,{available:!1,pendingApproval:!0,reason:"Chrome is running but remote debugging has not been approved yet",hint:"Open chrome://inspect/#remote-debugging in Chrome and click 'Allow' to approve the remote debugging connection.",fixCommand:`open -a 'Google Chrome' --args --remote-debugging-port=${x.port} --user-data-dir=/tmp/chrome-debug-profile`,port:x.port,debugPort:f});let{port:E,versionInfo:C}=x,R=C.Browser.match(/(\w+)\/(\d+)/),_=R?.[1]??"Chrome",P=R?parseInt(R[2],10):0;return P>0&&P<w?y(d,200,{available:!1,reason:`Chrome version ${P} is below minimum required version ${w}`,hint:`Update Chrome to version ${w} or higher`,version:C.Browser,port:E,browser:_,debugPort:f}):y(d,200,{available:!0,version:C.Browser,remoteDebugging:!0,port:E,browser:_,debugPort:f})}if(b==="POST"&&k==="/api/chrome-session/launch"){let p=await ne(v),m=M(),f=p.port??m.tools.chromeSession?.debugPort??9222,w=await It(f);if(w&&!w.pendingApproval){let P=w.versionInfo.Browser.match(/(\w+)\/(\d+)/);return y(d,200,{ok:!0,launched:!1,alreadyRunning:!0,port:w.port,version:w.versionInfo.Browser,browser:P?.[1]??"Chrome",message:`Chrome remote debugging is already active on port ${w.port}. No need to launch.`})}if(w?.pendingApproval)return y(d,200,{ok:!1,launched:!1,pendingApproval:!0,port:w.port,message:"Chrome is running on this port but remote debugging has not been approved yet. Open chrome://inspect/#remote-debugging in Chrome and click 'Allow'."});let x="/tmp/chrome-debug-profile",E=hl(x,"DevToolsActivePort");try{fl(E)}catch{}let C=process.platform,R,_=[`--remote-debugging-port=${f}`,`--user-data-dir=${x}`];if(C==="darwin"){let P=["/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",`${process.env.HOME}/Applications/Google Chrome.app/Contents/MacOS/Google Chrome`,"/Applications/Chromium.app/Contents/MacOS/Chromium","/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary","/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge","/Applications/Brave Browser.app/Contents/MacOS/Brave Browser"],V=P.find(D=>bt(D));if(!V)return y(d,500,{ok:!1,error:"No supported Chromium-based browser found",searched:P,hint:"Install Google Chrome or specify the path manually."});R=V}else if(C==="win32"){R="cmd.exe";let P=process.env.ProgramFiles??"C:\\Program Files",V=process.env.LOCALAPPDATA??"C:\\Users\\Default\\AppData\\Local",D=[`${P}\\Google\\Chrome\\Application\\chrome.exe`,`${V}\\Google\\Chrome\\Application\\chrome.exe`,`${P}\\Microsoft\\Edge\\Application\\msedge.exe`,`${V}\\Microsoft\\Edge\\Application\\msedge.exe`],me=D.find(Re=>bt(Re));if(!me)return y(d,500,{ok:!1,error:"No supported Chromium-based browser found",searched:D,hint:"Install Google Chrome or Microsoft Edge."});_=["/c","start","",me,`--remote-debugging-port=${f}`]}else{let P=["/usr/bin/google-chrome","/usr/bin/google-chrome-stable","/usr/bin/chromium","/usr/bin/chromium-browser","/snap/bin/chromium"],V=P.find(D=>bt(D));if(!V)return y(d,500,{ok:!1,error:"No supported Chromium-based browser found",searched:P,hint:"Install Google Chrome or Chromium."});R=V}try{let P=As(R,_,{detached:!0,stdio:"ignore"}),V=await Promise.race([new Promise(Re=>P.once("error",Re)),new Promise(Re=>setTimeout(()=>Re(null),500))]);if(V)return y(d,500,{ok:!1,error:V.message,chromePath:R,hint:"Could not launch Chrome. Please start Chrome manually with --remote-debugging-port=9222"});P.unref();let D;for(let Re=0;Re<5&&(await new Promise(st=>setTimeout(st,1e3)),D=await It(f),!D);Re++);if(!D)return y(d,200,{ok:!1,launched:!0,port:f,chromePath:R,message:"Chrome was launched but CDP is not fully active. You may need to click 'Allow' in Chrome's remote debugging prompt, or try closing all existing Chrome windows first, then retry."});if(D.pendingApproval)return y(d,200,{ok:!1,launched:!0,pendingApproval:!0,port:D.port,chromePath:R,message:"Chrome was launched but remote debugging has not been approved yet. Open chrome://inspect/#remote-debugging in Chrome and click 'Allow' to enable agent control."});let me=D.versionInfo.Browser.match(/(\w+)\/(\d+)/);return y(d,200,{ok:!0,launched:!0,port:D.port,chromePath:R,version:D.versionInfo.Browser,browser:me?.[1]??"Chrome",message:`Chrome launched successfully with remote debugging on port ${D.port}`})}catch(P){return y(d,500,{ok:!1,error:P instanceof Error?P.message:String(P),chromePath:R,hint:"Could not launch Chrome. Please start Chrome manually with --remote-debugging-port=9222"})}}if(b==="GET"&&k==="/api/browser-relay/status"){let m=M().tools.browserRelay;if(!m.enabled)return y(d,200,{enabled:!1,connected:!1,attachedTabs:[],extensionPath:m.extensionPath});if(o.browserRelay){let f=o.browserRelay.getStatus();return y(d,200,{enabled:!0,connected:f.connected,attachedTabs:f.attachedTabs,lastPing:f.lastPing,extensionPath:m.extensionPath})}return y(d,200,{enabled:m.enabled,connected:!1,attachedTabs:[],extensionPath:m.extensionPath})}if(b==="GET"&&k==="/api/browser-relay/config"){if(!$s(v,d,"Browser Relay bootstrap is only available from localhost."))return;let p=M(),m=p.tools.browserRelay;return y(d,200,{enabled:m.enabled,port:p.gateway.port,token:m.enabled&&m.authToken||""})}if(b==="POST"&&k==="/api/browser-relay/launch"){let p=await ne(v),m=M(),f=p.extensionPath??m.tools.browserRelay.extensionPath;if(!f)return y(d,400,{ok:!1,error:"No extension path configured",hint:"Set the extension path in Settings > Tools > Browser Relay"});let w=process.platform,x,E=[`--load-extension=${f}`,"--no-first-run","--no-default-browser-check"];if(w==="darwin")x=["/Applications/Google Chrome.app/Contents/MacOS/Google Chrome","/Applications/Chromium.app/Contents/MacOS/Chromium"].find(bt)??"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome";else if(w==="win32"){let C=process.env.ProgramFiles??"C:\\Program Files",R=process.env["ProgramFiles(x86)"]??"C:\\Program Files (x86)";x=[`${C}\\Google\\Chrome\\Application\\chrome.exe`,`${R}\\Google\\Chrome\\Application\\chrome.exe`].find(bt)??`${C}\\Google\\Chrome\\Application\\chrome.exe`}else x="google-chrome";try{return As(x,E,{detached:!0,stdio:"ignore"}).unref(),y(d,200,{ok:!0,launched:!0,extensionPath:f,message:`Chrome launched with extension from ${f}`})}catch(C){return y(d,500,{ok:!1,error:C instanceof Error?C.message:String(C),hint:"Could not launch Chrome. Please load the extension manually via chrome://extensions"})}}let I=k.match(/^\/api\/automations(?:\/([^/]+))?(\/run)?$/),F=X(o.config.agents.defaults.workspace);if(b==="GET"&&k==="/api/automations"){let p=Ot(F);return y(d,200,p)}if(b==="GET"&&I&&I[1]&&!I[2]){let p=I[1],m=Se(F,p);return m?y(d,200,m):y(d,404,{error:"Automation not found"})}if(b==="POST"&&k==="/api/automations"){let p=await ne(v);try{let m={name:String(p.name??"Untitled"),description:String(p.description??""),steps:p.steps||[],tags:p.tags||[],source:p.source||"manual"};p.toolType!==void 0&&(m.toolType=p.toolType),p.variables!==void 0&&(m.variables=p.variables);let f=Vn(F,m);return y(d,201,f)}catch(m){return y(d,400,{error:String(m)})}}if(b==="PUT"&&I&&I[1]&&!I[2]){let p=I[1],m=await ne(v),f={};m.name!==void 0&&(f.name=String(m.name)),m.description!==void 0&&(f.description=String(m.description)),m.enabled!==void 0&&(f.enabled=!!m.enabled),m.steps!==void 0&&(f.steps=m.steps),m.tags!==void 0&&(f.tags=m.tags),m.toolType!==void 0&&(f.toolType=m.toolType),m.variables!==void 0&&(f.variables=m.variables);let w=Xn(F,p,f);return w?y(d,200,w):y(d,404,{error:"Automation not found"})}if(b==="DELETE"&&I&&I[1]){let p=I[1];return $t(F,p)?y(d,200,{ok:!0}):y(d,404,{error:"Automation not found"})}if(b==="POST"&&I&&I[1]&&I[2]==="/run"){let p=I[1],m=Se(F,p);return m?m.enabled?(o.agent.tools.execute("automation",{command:"run",id:p}).then(f=>{console.log(`[automation] Execution of '${m.name}' finished`,{logs:f.kind==="ok"?f.content:f})}).catch(f=>{console.error(`[automation] Execution of '${m.name}' failed`,{err:f})}),y(d,200,{ok:!0,message:`Automation '${m.name}' execution started in background.`})):y(d,400,{error:"Automation is disabled"}):y(d,404,{error:"Automation not found"})}if(b==="GET"&&k==="/api/history"){let p=String($.searchParams.get("session")??"").trim(),m=h(p,"Session history not found.");if(m.error)return y(d,404,m.error);let f=m.sessionKey,w=o.sessionManager.getOrCreate(f);return y(d,200,{session:f,messages:Cr(w.messages)})}if(b==="GET"&&k==="/api/sessions"){let p=o.agent.getRuntimeState(),m=new Set((p.sessions||[]).filter(x=>x.running||x.queued>0).map(x=>x.key)),f=o.sessionManager.getOrCreate(o.sessionKey),w=o.sessionManager.listSessions().filter(x=>String(x.key??"")!==o.sessionKey).map(x=>{let E=String(x.key??"");return xr({key:E,created_at:String(x.created_at??f.createdAt),updated_at:String(x.updated_at??f.updatedAt)},o.sessionKey,m.has(E),o.sessionManager.getOrCreate(E))});return y(d,200,{currentSession:o.sessionKey,sessions:[xr({key:f.key,created_at:f.createdAt,updated_at:f.updatedAt},o.sessionKey,m.has(f.key),f),...w]})}if(b==="GET"&&k==="/api/files/preview"){let p=String($.searchParams.get("path")??"").trim(),m=parseInt($.searchParams.get("maxLines")??"100",10),f=o.workspacePath??process.cwd();if(!p)return y(d,400,{error:"path required"});try{je(p,f)}catch{return y(d,403,{error:"Access denied: path outside workspace"})}if(!bt(p))return y(d,404,{error:"file not found"});try{let w=de.statSync(p);if(w.isDirectory())return y(d,400,{error:"path is a directory"});let x=Es(p),E=de.readFileSync(p),C=null,R=!1;if(Ps(x)){let D=E.toString("utf-8").split(`
301
301
  `);R=D.length>m,C=D.slice(0,m).join(`
302
302
  `)}let _=ke.extname(p).toLowerCase(),P=x.startsWith("image/")?"image":x==="application/pdf"?"pdf":x==="text/csv"||x==="text/tab-separated-values"?"table":Ps(x)?_===".md"?"markdown":[".js",".mjs",".cjs",".ts",".tsx",".jsx",".py",".rb",".java",".go",".rs",".sh",".css",".html",".xml",".yml",".yaml"].includes(_)?"code":"text":"binary";return y(d,200,{name:ke.basename(p),path:p,size:w.size,content:C,truncated:R,mimeType:x,previewType:P,extension:_})}catch(w){return y(d,500,{error:String(w)})}}if(b==="GET"&&k==="/api/files/content"){let p=String($.searchParams.get("path")??"").trim(),m=o.workspacePath??process.cwd();if(!p)return y(d,400,{error:"path required"});try{je(p,m)}catch{return y(d,403,{error:"Access denied: path outside workspace"})}if(!bt(p))return y(d,404,{error:"file not found"});try{let f=de.statSync(p);if(f.isDirectory())return y(d,400,{error:"path is a directory"});d.statusCode=200,d.setHeader("Content-Type",Es(p)),d.setHeader("Content-Length",String(f.size)),de.createReadStream(p).pipe(d);return}catch(f){return y(d,500,{error:String(f)})}}if(b==="POST"&&k==="/api/sessions"){let p=await ne(v),m=new Set(o.sessionManager.listSessions().map(P=>String(P.key??"")));m.add(o.sessionKey);let f=String(p.key??"").trim(),w=[...m].map(P=>o.sessionManager.getOrCreate(P)),x=io(p.label),E=x||kl(w),C=f||xl(m,x),R=m.has(C),_=o.sessionManager.getOrCreate(C);return R||(_.metadata={..._.metadata,displayName:E},o.sessionManager.save(_)),y(d,200,{created:!R,session:xr({key:_.key,created_at:_.createdAt,updated_at:_.updatedAt},o.sessionKey,!1,_)})}if(Z&&b==="PUT"){let p=Z[1]?decodeURIComponent(Z[1]):void 0;if(!p)return y(d,400,"Invalid session key");let m=h(p,"Session not found.");if(m.error)return y(d,404,m.error);let f=await ne(v),w=io(f.label),x=Number(f.pinnedOrder),E=Number(f.recentOrder);if(w===void 0&&f.isPinned===void 0&&f.pinnedOrder===void 0&&f.recentOrder===void 0)return y(d,400,{error:"Session name, isPinned, pinnedOrder, or recentOrder is required.",session:p});let C=o.sessionManager.getOrCreate(m.sessionKey);if(C.metadata={...C.metadata},w!==void 0&&(C.metadata.displayName=w),f.isPinned!==void 0&&(C.metadata.isPinned=!!f.isPinned),C.metadata.isPinned===!0){delete C.metadata.recentOrder;let _=[...Is(o.sessionManager,C.key)],P=Number.isFinite(x)?Math.max(0,Math.min(Math.trunc(x),_.length)):_.length;_.splice(P,0,C),Ms(o.sessionManager,_),Os(o.sessionManager,_s(o.sessionManager,C.key))}else{delete C.metadata.pinnedOrder,Ms(o.sessionManager,Is(o.sessionManager,C.key));let _=[..._s(o.sessionManager,C.key)],P=Number.isFinite(E)?Math.max(0,Math.min(Math.trunc(E),_.length)):_.length;_.splice(P,0,C),Os(o.sessionManager,_)}return o.sessionManager.save(C),y(d,200,{ok:!0,session:xr({key:C.key,created_at:C.createdAt,updated_at:C.updatedAt},o.sessionKey,!1,C)})}if(Z&&b==="DELETE"){let p=Z[1]?decodeURIComponent(Z[1]):void 0;if(!p)return y(d,400,"Invalid session key");let m=h(p,"Session not found.");if(m.error)return y(d,404,m.error);if(m.sessionKey===o.sessionKey)return y(d,400,{error:"The primary session cannot be deleted."});let f=o.sessionManager.delete(m.sessionKey);return y(d,200,{ok:f,session:p})}if(b==="GET"&&k==="/api/suggestions"){let p=String($.searchParams.get("session")??"").trim(),m=h(p,"Session suggestions not found.");if(m.error)return y(d,404,m.error);let f=m.sessionKey,w=o.sessionManager.getOrCreate(f),x=M(),E=x.subagents?.find(R=>R.id==="advisor"),C=E?E.task:"Analyze the conversation and suggest 3 possible next messages the user could send. Return a JSON array of strings.";try{let R=_e(x),_=await Qr({task:C+`
303
303
  Return ONLY a JSON array of strings, nothing else.`,provider:R,workspace:o.workspacePath??process.cwd(),model:x.agents.defaults.model,temperature:.3,maxTokens:500,braveApiKey:null,execConfig:x.tools.exec,restrictToWorkspace:x.tools.restrictToWorkspace,existingMessages:Cr(w.messages)}),P=[];try{let D=_.replace(/```json/g,"").replace(/```/g,"").trim();P=JSON.parse(D)}catch{P=so(w.messages).map(D=>D.text)}let V=Array.isArray(P)?P.slice(0,3).map((D,me)=>({id:`suggestion-${me+1}`,text:String(D),label:Tr(String(D),56)??String(D)})):so(w.messages);return y(d,200,{session:f,suggestions:V})}catch{return y(d,200,{session:f,suggestions:so(w.messages)})}}if(b==="GET"&&k==="/api/session-files"){let p=String($.searchParams.get("session")??"").trim(),m=h(p,"Session files not found.");return m.error?y(d,404,m.error):y(d,200,{session:m.sessionKey,files:c().list(m.sessionKey)})}if(b==="GET"&&k==="/api/inbox-deliveries"){let p=$.searchParams.get("all")==="1",m=u();if(m.list({includeCleared:!0}).filter(x=>!x.clearedAt).length===0){let x=[{jobId:"demo-cron-daily-standup",jobName:"Daily standup reminder",sessionKey:"default:everclaw",channel:"cli",recipient:"direct",content:`This is a sample cron notification to demonstrate the Inbox functionality. When real cron jobs run and deliver messages, they will appear here.
304
304
 
305
305
  This delivery is from a demo cron job that runs daily to remind the team about the standup meeting.`},{jobId:"demo-cron-weekly-report",jobName:"Weekly progress report",sessionKey:"telegram:8281248569",channel:"telegram",recipient:"8281248569",content:"Your weekly progress report is ready. This demo delivery shows how proactive notifications from cron jobs appear in your inbox. You can clear this delivery once reviewed."},{jobId:"demo-cron-backup",jobName:"Backup completed",sessionKey:"default:everclaw",channel:"cli",recipient:"direct",content:"Automated backup completed successfully at 3:00 AM. All project files have been archived to the backup location. This is a demo delivery for testing the inbox clear functionality."}],E=new Date;for(let C=0;C<x.length;C++){let R=x[C],_=new Date(E.getTime()-C*36e5).toISOString();m.record({jobId:R.jobId,jobName:R.jobName,sessionKey:R.sessionKey,channel:R.channel,recipient:R.recipient,content:R.content,deliveredAt:_})}}return y(d,200,{deliveries:m.list({includeCleared:p})})}if(ae&&b==="GET"){let p=ae[1];if(!p)return y(d,400,"Invalid delivery ID");let m=u().get(decodeURIComponent(p));return m?y(d,200,{delivery:m}):y(d,404,{error:"Inbox delivery not found."})}if(J&&b==="POST"){let p=J[1];if(!p)return y(d,400,"Invalid delivery ID");let m=u().markCleared(decodeURIComponent(p));return m?y(d,200,{ok:!0,delivery:m}):y(d,404,{error:"Inbox delivery not found."})}if(b==="POST"&&k==="/api/session-files"){let p=await ne(v),m=String(p.session??"").trim(),f=h(m,"Session files not found.");if(f.error)return y(d,404,f.error);try{return y(d,200,c().associate(f.sessionKey,String(p.path??"")))}catch(w){return y(d,400,{error:w instanceof Error?w.message:String(w)})}}if(b==="POST"&&k==="/api/session-files/upload"){let p=await ne(v),m=String(p.session??"").trim(),f=h(m,"Session files not found.");if(f.error)return y(d,404,f.error);let w=String(p.filename??"").trim(),x=String(p.content??"").trim();if(!w)return y(d,400,{error:"Filename is required."});if(!x)return y(d,400,{error:"File content is required."});let E=[".md",".txt",".pdf",".jpg",".jpeg",".png",".gif",".webp",".json",".js",".jsx",".ts",".tsx",".css",".html",".xml",".yml",".yaml",".py",".rb",".go",".rs",".java",".c",".cc",".cpp",".h",".hpp",".sh"],C=w.toLowerCase().slice(w.lastIndexOf("."));if(!C||!E.includes(C))return y(d,400,{error:`Unsupported file type. Allowed: ${E.join(", ")}`});try{let R=Buffer.from(x,"base64"),_=ke.join(o.workspacePath??process.cwd(),".session-uploads");de.existsSync(_)||de.mkdirSync(_,{recursive:!0});let P=w.replace(/[^a-zA-Z0-9._-]/g,"_"),V=ke.join(_,`${Date.now()}-${P}`);return de.writeFileSync(V,R),y(d,200,c().associate(f.sessionKey,V))}catch(R){return y(d,400,{error:R instanceof Error?R.message:String(R)})}}if(b==="POST"&&k==="/api/session-files/copy-local"){let p=await ne(v),m=String(p.session??"").trim(),f=h(m,"Session files not found.");if(f.error)return y(d,404,f.error);let w=String(p.path??"").trim(),x=o.workspacePath??process.cwd();if(!w)return y(d,400,{error:"Path is required."});try{je(w,x)}catch{return y(d,403,{error:"Access denied: path outside workspace"})}if(!de.existsSync(w))return y(d,404,{error:"File not found."});try{return de.statSync(w).isDirectory()?y(d,400,{error:"Path is a directory."}):y(d,200,c().associate(f.sessionKey,w))}catch(E){return y(d,400,{error:E instanceof Error?E.message:String(E)})}}if(A&&b==="GET"){let p=String($.searchParams.get("session")??"").trim(),m=h(p,"Session files not found.");if(m.error)return y(d,404,m.error);let f=A[1];if(!f)return y(d,400,"Invalid file ID");let w=c().get(m.sessionKey,decodeURIComponent(f));return w?y(d,200,{session:m.sessionKey,file:w}):y(d,404,{error:"Session file not found.",session:m.sessionKey})}if(A&&b==="DELETE"){let p=String($.searchParams.get("session")??"").trim(),m=h(p,"Session files not found.");if(m.error)return y(d,404,m.error);let f=A[1];return f?y(d,200,{ok:c().remove(m.sessionKey,decodeURIComponent(f))}):y(d,400,"Invalid file ID")}if(b==="POST"&&k==="/api/chat/stream"){let p=await ne(v),m=p.message,f=String(p.session??"default:everclaw"),w=String(p.model??"").trim(),x=String(p._provider??"").trim(),E=Array.isArray(m)?m:String(m??"").trim();if(typeof E=="string"&&!E)return y(d,400,{error:"message required"});if(Array.isArray(E)&&E.length===0)return y(d,400,{error:"message required"});d.setHeader("Content-Type","text/event-stream"),d.setHeader("Cache-Control","no-cache"),d.setHeader("Connection","keep-alive"),d.flushHeaders();let C=P=>{d.write(`data: ${JSON.stringify(P)}
306
306
 
307
- `)},R="",_=[];try{let P=await o.agent.processDirectResult(E,f,"cli","dashboard",async(V,D)=>{if(D?.thinkingContent&&(R=D.thinkingContent),Array.isArray(D?.tool_calls)&&(_=D.tool_calls),D?.tool_call&&typeof D.tool_call=="object"){let me=D.tool_call,Re=typeof me.id=="string"?me.id:"";_=_.some(st=>st.id===Re)?_.map(st=>st.id===Re?{...st,...me}:st):[..._,me]}switch(D?.event){case"thinking":C({type:"thinking",content:D.thinkingContent??V});break;case"tool_calls":C({type:"tool_calls",tool_calls:_});break;case"tool_result":C({type:"tool_result",tool_call:D.tool_call,tool_calls:_});break;case"answer":C({type:"answer",content:V});break;default:C({type:"progress",content:V,toolHint:!!D?.toolHint,...D?.tool_calls?{tool_calls:D.tool_calls}:{}});break}},{...w?{_model:w}:{},...x?{_provider:x}:{},...Array.isArray(p.skillNames)&&p.skillNames.length?{skillNames:p.skillNames}:{}});P.outcome==="rate_limited"?C({type:"error",error:P.content,outcome:P.outcome,retryAfterMs:P.retryAfterMs??0}):P.outcome==="backpressure"||P.outcome==="shutdown"?C({type:"error",error:P.content,outcome:P.outcome}):C({type:"done",response:P.content,thinkingContent:R,tool_calls:_})}catch(P){C({type:"error",error:String(P)})}finally{d.end()}return}if(b==="POST"&&k==="/api/chat"){let p=await ne(v),m=p.message,f=String(p.session??"default:everclaw"),w=String(p.model??"").trim(),x=String(p._provider??"").trim(),E=Array.isArray(m)?m:String(m??"").trim();if(typeof E=="string"&&!E)return y(d,400,{error:"message required"});if(Array.isArray(E)&&E.length===0)return y(d,400,{error:"message required"});let C=[];try{let R=await o.agent.processDirectResult(E,f,"cli","dashboard",async(_,P)=>{C.push({content:_,toolHint:!!P?.toolHint,...P?.tool_calls?{tool_calls:P.tool_calls}:{}})},{...w?{_model:w}:{},...x?{_provider:x}:{}});return R.outcome==="rate_limited"?(d.setHeader("Retry-After",String(Math.max(1,Math.ceil((R.retryAfterMs??0)/1e3)))),y(d,429,{error:R.content,outcome:R.outcome,retryAfterMs:R.retryAfterMs??0,progress:C})):R.outcome==="backpressure"||R.outcome==="shutdown"?y(d,503,{error:R.content,outcome:R.outcome,progress:C}):y(d,200,{response:R.content,progress:C})}catch(R){return y(d,500,{error:String(R)})}}if(b==="GET"&&k==="/api/config")return y(d,200,Rl(M()));if(b==="GET"&&k==="/api/security/status"){let{ToolGuardEngine:p}=await Promise.resolve().then(()=>(oo(),Rs)),f=p.getInstance().getRules(),w=f.filter(E=>E.enabled),x=M();return y(d,200,{toolGuard:{enabled:x.security?.toolGuard?.enabled??!1,totalRules:f.length,enabledRules:w.length,defaultRules:f.filter(E=>!E.id.startsWith("user-")).length,userRules:x.security?.toolGuard?.rules?.length??0},skillScanner:{enabled:x.security?.skillScanner?.enabled??!1}})}if(b==="PUT"&&k==="/api/config"){let p=await ne(v),m=et(p.config)?p.config:null;if(!m)return y(d,400,{error:"Request body must include a config object."});let f=Pl(m),w=M(),x=p.secretChanges;w.security?.auth&&f.security?.auth&&"pinHash"in w.security.auth&&(f.security.auth.pinHash=w.security.auth.pinHash);try{if(f.providers&&w.providers)for(let C of Object.keys(f.providers))f.providers[C]&&w.providers[C]&&vt(f,w,x,["providers",C,"apiKey"]);if(Array.isArray(f.customLlmProviders)&&Array.isArray(w.customLlmProviders))for(let C=0;C<f.customLlmProviders.length;C++){let R=f.customLlmProviders[C];if(!R)continue;let P=w.customLlmProviders.find(me=>me?.name===R.name)?.apiKey??"",V=R.apiKey??"",D=Ns(x,["customLlmProviders",C,"apiKey"],P,V);D&&(R.apiKey=D.action==="keep"?P:D.action==="clear"?"":D.value??V)}if(f.channels&&w.channels&&(vt(f,w,x,["channels","telegram","token"]),vt(f,w,x,["channels","discord","token"])),f.tools?.browserRelay&&w.tools?.browserRelay&&vt(f,w,x,["tools","browserRelay","authToken"]),f.tools?.web?.search&&w.tools?.web?.search&&vt(f,w,x,["tools","web","search","apiKey"]),f.tools?.mcpServers&&w.tools?.mcpServers)for(let C of Object.keys(f.tools.mcpServers)){let R=f.tools.mcpServers[C];if(R?.env)for(let _ of Object.keys(R.env))vt(f,w,x,["tools","mcpServers",C,"env",_]);if(R?.headers)for(let _ of Object.keys(R.headers))vt(f,w,x,["tools","mcpServers",C,"headers",_])}}catch(C){return y(d,400,{error:C instanceof Error?C.message:String(C)})}if(f.security?.auth?.enabled&&!f.security?.auth?.pinHash?.length)return y(d,400,{error:"Cannot enable PIN authentication without setting a PIN. Use the 'Set PIN' button first.",field:"security.auth.enabled"});let E=El(f.tools?.mcpServers??{});return E.length?y(d,400,{error:`Invalid MCP server configuration. ${E[0]}`,details:E}):(oe(f),l.updateConfig(f.security.auth),y(d,200,{ok:!0}))}if(b==="GET"&&k==="/api/subagents"){let p=M();return y(d,200,{subagents:p.subagents||[]})}if(b==="POST"&&k==="/api/subagents"){let p=await ne(v),m=M();m.subagents||(m.subagents=[]);let f=m.subagents.length,w={id:`subagent-${Date.now()}`,name:p.name||`SubAgent ${f+1}`,task:p.task||"",createdAt:Date.now()};return m.subagents.push(w),oe(m),y(d,200,w)}let q=k.match(/^\/api\/subagents\/([^/]+)$/);if(q&&b==="PUT"){let p=q[1];if(!p)return y(d,400,"Invalid subagent ID");let m=await ne(v),f=M();f.subagents||(f.subagents=[]);let w=f.subagents.findIndex(C=>C.id===p);if(w===-1)return y(d,404,{error:"Subagent not found"});let x=f.subagents[w];if(!x)return y(d,404,{error:"Subagent not found"});let E={id:m.id??x.id,name:m.name??x.name,task:m.task??x.task,createdAt:m.createdAt??x.createdAt};return f.subagents[w]=E,oe(f),y(d,200,E)}if(q&&b==="DELETE"){let p=q[1],m=M();m.subagents||(m.subagents=[]);let f=m.subagents.findIndex(w=>w.id===p);return f===-1?y(d,404,{error:"Subagent not found"}):(m.subagents.splice(f,1),oe(m),y(d,200,{ok:!0}))}if(b==="GET"&&k==="/api/skills")try{return y(d,200,n.getSnapshot())}catch(p){return y(d,500,{error:String(p)})}if(b==="POST"&&k==="/api/skills/install"){let p=await ne(v);try{let m=await n.install(String(p.slug??""));return y(d,200,m)}catch(m){return y(d,400,{error:m instanceof Error?m.message:String(m)})}}if(b==="GET"&&k==="/api/cron/jobs"){let p=$.searchParams.get("all")==="1";return y(d,200,o.cron.listJobs(p))}if(b==="POST"&&k==="/api/cron/jobs"){let p=await ne(v);try{let m={name:String(p.name??"job"),schedule:p.schedule,message:String(p.message??""),deliver:!!p.deliver,deleteAfterRun:!!p.deleteAfterRun};p.channel&&(m.channel=String(p.channel)),p.to&&(m.to=String(p.to));let f=o.cron.addJob(m);return y(d,200,f)}catch(m){return y(d,400,{error:String(m)})}}if(N&&b==="DELETE"){let p=N[1];return p?y(d,200,{ok:o.cron.removeJob(p)}):y(d,400,"Invalid job ID")}if(N&&b==="PUT"){let p=N[1];if(!p)return y(d,400,"Invalid job ID");let m=await ne(v),f={};m.name!==void 0&&(f.name=String(m.name)),m.schedule!==void 0&&(f.schedule=m.schedule),m.message!==void 0&&(f.message=String(m.message)),m.deliver!==void 0&&(f.deliver=!!m.deliver),m.channel!==void 0&&(f.channel=String(m.channel)),m.to!==void 0&&(f.to=String(m.to)),m.deleteAfterRun!==void 0&&(f.deleteAfterRun=!!m.deleteAfterRun);let w=o.cron.updateJob(p,f);return w?y(d,200,w):y(d,404,{error:"not found"})}if(z&&b==="POST"){let m=(await ne(v)).enabled!==!1,f=z[1];if(!f)return y(d,400,"Invalid job ID");let w=o.cron.enableJob(f,m);return w?y(d,200,w):y(d,404,{error:"not found"})}if(F&&b==="POST"){let p=await ne(v),m=F[1];if(!m)return y(d,400,"Invalid job ID");let f=await o.cron.runJob(m,!!p.force);return y(d,200,{ok:f})}let re=o.config.gateway.dashboard?.enabled!==!1;if(re&&e){let p=ke.resolve(e,k==="/"?"index.html":k.slice(1));if(!p.startsWith(ke.resolve(e)+ke.sep)&&p!==ke.resolve(e)&&(p=ke.join(e,"index.html")),(!de.existsSync(p)||de.statSync(p).isDirectory())&&(p=ke.join(e,"index.html")),!de.existsSync(p)){d.statusCode=404,d.end("Dashboard assets not found. Run npm run build.");return}d.statusCode=200,d.setHeader("Content-Type",Cl(p)),de.createReadStream(p).pipe(d);return}if(!k.startsWith("/api/")){d.statusCode=404,d.end(re?"Dashboard assets not found. Install the full package or run `npm run build:dashboard`.":"Dashboard is disabled. API endpoints are still available.");return}d.statusCode=404,d.end("Dashboard is disabled. API endpoints are still available.")});return T.listen(t,o.config.gateway.host),o.browserRelay&&(o.browserRelay.attachToServer(T),console.log("[gateway] Browser relay WebSocket endpoint mounted at /ws/browser-relay")),{beginShutdown:()=>{i=!0},port:t,close:()=>(i=!0,new Promise((v,d)=>T.close(b=>{try{r?.close(),s?.close()}catch{}b?d(b):v()})))}}le();import{spawn as Rr}from"node:child_process";import{createWriteStream as _l,existsSync as Gt,lstatSync as Ol,mkdirSync as $l,readdirSync as Ll,rmSync as pn}from"node:fs";import Ar from"node:path";import{pipeline as Dl}from"node:stream/promises";var Ce="0.28.0",Fs="https://github.com/rtk-ai/rtk/releases",Bs=3e4,Er={"darwin-arm64":"rtk-aarch64-apple-darwin.tar.gz","darwin-x64":"rtk-x86_64-apple-darwin.tar.gz","linux-arm64":"rtk-aarch64-unknown-linux-gnu.tar.gz","linux-x64":"rtk-x86_64-unknown-linux-musl.tar.gz","win32-x64":"rtk-x86_64-pc-windows-msvc.zip"},Nl=200,jl=5e3;function Gs(o){return Math.ceil(o.length/4)}function wt(o,e){let t=c=>c.split(".").map(u=>parseInt(u,10)||0),[n=0,r=0,s=0]=t(o),[i=0,a=0,l=0]=t(e);return n!==i?n>=i:r!==a?r>=a:s>=l}var Te=class o{runtime={available:!1,binaryPath:"",version:null};static binaryPath(){let e=process.platform==="win32"?"rtk.exe":"rtk";return Ar.join(fn(),"bin",e)}async resolve(e){if(!e.enabled)return this.runtime={available:!1,binaryPath:"",version:null},this.runtime;let t=o.binaryPath();if(Gt(t)){let n=await this.getVersion(t);if(n&&wt(n,Ce))return this.runtime={available:!0,binaryPath:t,version:n},this.runtime;if(e.autoInstall&&process.env.CI!=="true"){console.error(`[rtk] Binary outdated (${n}, need ${Ce}). Re-downloading...`);try{return await this.install({version:e.version,force:!0})}catch(r){return console.error(`[rtk] Failed to re-download: ${r instanceof Error?r.message:String(r)}`),this.runtime={available:!1,binaryPath:"",version:null},this.runtime}}return this.runtime={available:!1,binaryPath:"",version:null},this.runtime}if(e.autoInstall&&process.env.CI!=="true")try{return await this.install({version:e.version})}catch(n){return console.error(`[rtk] Auto-download failed: ${n instanceof Error?n.message:String(n)}`),this.runtime={available:!1,binaryPath:"",version:null},this.runtime}return this.runtime={available:!1,binaryPath:"",version:null},this.runtime}async install(e){let t=e?.version??"latest",n=`${process.platform}-${process.arch}`,r=Er[n];if(!r)throw new Error(`Unsupported platform: ${n}. Supported platforms: ${Object.keys(Er).join(", ")}`);let s=o.binaryPath(),i=Ar.dirname(s);if(!e?.force&&Gt(s)){let c=await this.getVersion(s);if(c&&wt(c,Ce))return this.runtime={available:!0,binaryPath:s,version:c},this.runtime}let a;if(t==="latest")a=`${Fs}/latest/download/${r}`;else{let c=`v${t.replace(/^v/,"")}`;a=`${Fs}/download/${c}/${r}`}console.error(`[rtk] Downloading from ${a}...`),Gt(i)||$l(i,{recursive:!0});let l=Ar.join(i,`.rtk-download-${Date.now()}.${r.endsWith(".zip")?"zip":"tar.gz"}`);try{if(await this.downloadFile(a,l),r.endsWith(".zip")?await this.extractZip(l,s):await this.extractTarGz(l,s),process.platform!=="win32"){let{chmodSync:u}=await import("node:fs");u(s,493)}let c=await this.getVersion(s);if(!c)throw new Error("Downloaded binary failed version check");return console.error(`[rtk] Installed v${c} to ${s}`),this.runtime={available:!0,binaryPath:s,version:c},this.runtime}finally{Gt(l)&&pn(l,{force:!0})}}async downloadFile(e,t){let{Readable:n}=await import("node:stream"),r=new AbortController,s=setTimeout(()=>r.abort(),Bs);try{let i=await fetch(e,{redirect:"follow",signal:r.signal});if(!i.ok)throw new Error(`Download failed: ${i.status} ${i.statusText}`);if(!i.body)throw new Error("Download failed: No response body");await Dl(n.fromWeb(i.body),_l(t))}catch(i){throw pn(t,{force:!0}),i instanceof Error&&i.name==="AbortError"?new Error(`Download timed out after ${Bs}ms`):i}finally{clearTimeout(s)}}async extractTarGz(e,t){let{renameSync:n}=await import("node:fs"),{mkdtemp:r}=await import("node:fs/promises"),{tmpdir:s}=await import("node:os"),{join:i}=await import("node:path");if(process.platform==="win32")throw new Error("tar.gz extraction on Windows is not supported \u2014 use .zip assets");let a=await r(i(s(),"rtk-extract-"));try{let l=Rr("tar",["-xzf",e,"-C",a],{stdio:["ignore","pipe","pipe"]});await new Promise((u,g)=>{l.on("close",h=>{h===0?u():g(new Error(`tar extraction failed with code ${h}`))}),l.on("error",g)});let c=this.findBinaryInDir(a,"rtk");if(!c)throw new Error("Could not find rtk binary in extracted archive");n(c,t)}finally{pn(a,{recursive:!0,force:!0})}}findBinaryInDir(e,t){let n=process.platform==="win32"?[`${t}.exe`,t]:[t];for(let r of Ll(e)){let s=Ar.join(e,r),i=Ol(s);if(!i.isSymbolicLink()){if(i.isFile()&&n.includes(r))return s;if(i.isDirectory()){let a=this.findBinaryInDir(s,t);if(a)return a}}}return null}async extractZip(e,t){let{renameSync:n}=await import("node:fs"),{mkdtemp:r}=await import("node:fs/promises"),{tmpdir:s}=await import("node:os"),{join:i}=await import("node:path"),a=await r(i(s(),"rtk-extract-"));try{let l=Rr("powershell",["-Command",`Expand-Archive -LiteralPath '${e.replace(/'/g,"''")}' -DestinationPath '${a.replace(/'/g,"''")}' -Force`]);await new Promise((u,g)=>{l.on("close",h=>{h===0?u():g(new Error(`PowerShell extraction failed with code ${h}`))}),l.on("error",g)});let c=this.findBinaryInDir(a,"rtk");if(!c)throw new Error("Could not find rtk binary in extracted archive");n(c,t)}finally{pn(a,{recursive:!0,force:!0})}}async uninstall(){let e=o.binaryPath();Gt(e)&&pn(e,{force:!0}),this.runtime={available:!1,binaryPath:"",version:null}}getRuntime(){return this.runtime}async getStatus(){let e=o.binaryPath();return Gt(e)?{installed:!0,version:await this.getVersion(e),binaryPath:e}:{installed:!1,version:null,binaryPath:e}}async getVersion(e){return new Promise(t=>{let n=Rr(e,["--version"]),r="";n.stdout?.on("data",s=>{r+=s.toString()}),n.on("close",s=>{if(s===0){let i=r.match(/(\d+\.\d+\.\d+)/);t(i?i[1]??null:r.trim()||null)}else t(null)}),n.on("error",()=>t(null))})}async compress(e){if(!this.runtime.available)return{stdout:e.stdout,stderr:e.stderr,compressed:!1,originalTokens:0,compressedTokens:0};if(e.stdout.length<Nl)return{stdout:e.stdout,stderr:e.stderr,compressed:!1,originalTokens:0,compressedTokens:0};let t=Gs(e.stdout);try{let n=await this.runRtkSummary(e.stdout,e.ultraCompact),r=Gs(n);return{stdout:n,stderr:e.stderr,compressed:!0,originalTokens:t,compressedTokens:r}}catch{return{stdout:e.stdout,stderr:e.stderr,compressed:!1,originalTokens:0,compressedTokens:0}}}async runRtkSummary(e,t){return new Promise((n,r)=>{let s=t?["-u","summary"]:["summary"],i=Rr(this.runtime.binaryPath,s),a="",l="",c=setTimeout(()=>{i.kill("SIGKILL"),r(new Error("rtk compression timed out"))},jl);i.stdout?.on("data",u=>{a+=u.toString()}),i.stderr?.on("data",u=>{l+=u.toString()}),i.stdin?.end(e,"utf8"),i.on("close",u=>{clearTimeout(c),u===0?n(a):r(new Error(`rtk exited with code ${u}: ${l}`))}),i.on("error",u=>{clearTimeout(c),r(u)})})}};import{randomUUID as Fl}from"node:crypto";import co,{WebSocketServer as Bl}from"ws";var uo=class{wss=null;extension=null;config;onStatusChange;constructor(e,t){this.config=e,this.onStatusChange=t}handleUpgrade(e,t,n){if(!this.wss){t.destroy();return}let s=new URL(e.url||"/",`http://${e.headers.host||"localhost"}`).searchParams.get("token");if(!this.config.enabled){t.write(`HTTP/1.1 503 Service Unavailable\r
307
+ `)},R="",_=[];try{let P=await o.agent.processDirectResult(E,f,"cli","dashboard",async(V,D)=>{if(D?.thinkingContent&&(R=D.thinkingContent),Array.isArray(D?.tool_calls)&&(_=D.tool_calls),D?.tool_call&&typeof D.tool_call=="object"){let me=D.tool_call,Re=typeof me.id=="string"?me.id:"";_=_.some(st=>st.id===Re)?_.map(st=>st.id===Re?{...st,...me}:st):[..._,me]}switch(D?.event){case"thinking":C({type:"thinking",content:D.thinkingContent??V});break;case"tool_calls":C({type:"tool_calls",tool_calls:_});break;case"tool_result":C({type:"tool_result",tool_call:D.tool_call,tool_calls:_});break;case"answer":C({type:"answer",content:V});break;default:C({type:"progress",content:V,toolHint:!!D?.toolHint,...D?.tool_calls?{tool_calls:D.tool_calls}:{}});break}},{...w?{_model:w}:{},...x?{_provider:x}:{},...Array.isArray(p.skillNames)&&p.skillNames.length?{skillNames:p.skillNames}:{}});P.outcome==="rate_limited"?C({type:"error",error:P.content,outcome:P.outcome,retryAfterMs:P.retryAfterMs??0}):P.outcome==="backpressure"||P.outcome==="shutdown"?C({type:"error",error:P.content,outcome:P.outcome}):C({type:"done",response:P.content,thinkingContent:R,tool_calls:_})}catch(P){C({type:"error",error:String(P)})}finally{d.end()}return}if(b==="POST"&&k==="/api/chat"){let p=await ne(v),m=p.message,f=String(p.session??"default:everclaw"),w=String(p.model??"").trim(),x=String(p._provider??"").trim(),E=Array.isArray(m)?m:String(m??"").trim();if(typeof E=="string"&&!E)return y(d,400,{error:"message required"});if(Array.isArray(E)&&E.length===0)return y(d,400,{error:"message required"});let C=[];try{let R=await o.agent.processDirectResult(E,f,"cli","dashboard",async(_,P)=>{C.push({content:_,toolHint:!!P?.toolHint,...P?.tool_calls?{tool_calls:P.tool_calls}:{}})},{...w?{_model:w}:{},...x?{_provider:x}:{}});return R.outcome==="rate_limited"?(d.setHeader("Retry-After",String(Math.max(1,Math.ceil((R.retryAfterMs??0)/1e3)))),y(d,429,{error:R.content,outcome:R.outcome,retryAfterMs:R.retryAfterMs??0,progress:C})):R.outcome==="backpressure"||R.outcome==="shutdown"?y(d,503,{error:R.content,outcome:R.outcome,progress:C}):y(d,200,{response:R.content,progress:C})}catch(R){return y(d,500,{error:String(R)})}}if(b==="GET"&&k==="/api/config")return y(d,200,Rl(M()));if(b==="GET"&&k==="/api/security/status"){let{ToolGuardEngine:p}=await Promise.resolve().then(()=>(oo(),Rs)),f=p.getInstance().getRules(),w=f.filter(E=>E.enabled),x=M();return y(d,200,{toolGuard:{enabled:x.security?.toolGuard?.enabled??!1,totalRules:f.length,enabledRules:w.length,defaultRules:f.filter(E=>!E.id.startsWith("user-")).length,userRules:x.security?.toolGuard?.rules?.length??0},skillScanner:{enabled:x.security?.skillScanner?.enabled??!1}})}if(b==="PUT"&&k==="/api/config"){let p=await ne(v),m=et(p.config)?p.config:null;if(!m)return y(d,400,{error:"Request body must include a config object."});let f=Pl(m),w=M(),x=p.secretChanges;w.security?.auth&&f.security?.auth&&"pinHash"in w.security.auth&&(f.security.auth.pinHash=w.security.auth.pinHash);try{if(f.providers&&w.providers)for(let C of Object.keys(f.providers))f.providers[C]&&w.providers[C]&&vt(f,w,x,["providers",C,"apiKey"]);if(Array.isArray(f.customLlmProviders)&&Array.isArray(w.customLlmProviders))for(let C=0;C<f.customLlmProviders.length;C++){let R=f.customLlmProviders[C];if(!R)continue;let P=w.customLlmProviders.find(me=>me?.name===R.name)?.apiKey??"",V=R.apiKey??"",D=Ns(x,["customLlmProviders",C,"apiKey"],P,V);D&&(R.apiKey=D.action==="keep"?P:D.action==="clear"?"":D.value??V)}if(f.channels&&w.channels&&(vt(f,w,x,["channels","telegram","token"]),vt(f,w,x,["channels","discord","token"])),f.tools?.browserRelay&&w.tools?.browserRelay&&vt(f,w,x,["tools","browserRelay","authToken"]),f.tools?.web?.search&&w.tools?.web?.search&&vt(f,w,x,["tools","web","search","apiKey"]),f.tools?.mcpServers&&w.tools?.mcpServers)for(let C of Object.keys(f.tools.mcpServers)){let R=f.tools.mcpServers[C];if(R?.env)for(let _ of Object.keys(R.env))vt(f,w,x,["tools","mcpServers",C,"env",_]);if(R?.headers)for(let _ of Object.keys(R.headers))vt(f,w,x,["tools","mcpServers",C,"headers",_])}}catch(C){return y(d,400,{error:C instanceof Error?C.message:String(C)})}if(f.security?.auth?.enabled&&!f.security?.auth?.pinHash?.length)return y(d,400,{error:"Cannot enable PIN authentication without setting a PIN. Use the 'Set PIN' button first.",field:"security.auth.enabled"});let E=El(f.tools?.mcpServers??{});return E.length?y(d,400,{error:`Invalid MCP server configuration. ${E[0]}`,details:E}):(oe(f),l.updateConfig(f.security.auth),y(d,200,{ok:!0}))}if(b==="GET"&&k==="/api/subagents"){let p=M();return y(d,200,{subagents:p.subagents||[]})}if(b==="POST"&&k==="/api/subagents"){let p=await ne(v),m=M();m.subagents||(m.subagents=[]);let f=m.subagents.length,w={id:`subagent-${Date.now()}`,name:p.name||`SubAgent ${f+1}`,task:p.task||"",createdAt:Date.now()};return m.subagents.push(w),oe(m),y(d,200,w)}let q=k.match(/^\/api\/subagents\/([^/]+)$/);if(q&&b==="PUT"){let p=q[1];if(!p)return y(d,400,"Invalid subagent ID");let m=await ne(v),f=M();f.subagents||(f.subagents=[]);let w=f.subagents.findIndex(C=>C.id===p);if(w===-1)return y(d,404,{error:"Subagent not found"});let x=f.subagents[w];if(!x)return y(d,404,{error:"Subagent not found"});let E={id:m.id??x.id,name:m.name??x.name,task:m.task??x.task,createdAt:m.createdAt??x.createdAt};return f.subagents[w]=E,oe(f),y(d,200,E)}if(q&&b==="DELETE"){let p=q[1],m=M();m.subagents||(m.subagents=[]);let f=m.subagents.findIndex(w=>w.id===p);return f===-1?y(d,404,{error:"Subagent not found"}):(m.subagents.splice(f,1),oe(m),y(d,200,{ok:!0}))}if(b==="GET"&&k==="/api/skills")try{return y(d,200,n.getSnapshot())}catch(p){return y(d,500,{error:String(p)})}if(b==="POST"&&k==="/api/skills/install"){let p=await ne(v);try{let m=await n.install(String(p.slug??""));return y(d,200,m)}catch(m){return y(d,400,{error:m instanceof Error?m.message:String(m)})}}if(b==="GET"&&k==="/api/cron/jobs"){let p=$.searchParams.get("all")==="1";return y(d,200,o.cron.listJobs(p))}if(b==="POST"&&k==="/api/cron/jobs"){let p=await ne(v);try{let m={name:String(p.name??"job"),schedule:p.schedule,message:String(p.message??""),deliver:!!p.deliver,deleteAfterRun:!!p.deleteAfterRun};p.channel&&(m.channel=String(p.channel)),p.to&&(m.to=String(p.to));let f=o.cron.addJob(m);return y(d,200,f)}catch(m){return y(d,400,{error:String(m)})}}if(N&&b==="DELETE"){let p=N[1];return p?y(d,200,{ok:o.cron.removeJob(p)}):y(d,400,"Invalid job ID")}if(N&&b==="PUT"){let p=N[1];if(!p)return y(d,400,"Invalid job ID");let m=await ne(v),f={};m.name!==void 0&&(f.name=String(m.name)),m.schedule!==void 0&&(f.schedule=m.schedule),m.message!==void 0&&(f.message=String(m.message)),m.deliver!==void 0&&(f.deliver=!!m.deliver),m.channel!==void 0&&(f.channel=String(m.channel)),m.to!==void 0&&(f.to=String(m.to)),m.deleteAfterRun!==void 0&&(f.deleteAfterRun=!!m.deleteAfterRun);let w=o.cron.updateJob(p,f);return w?y(d,200,w):y(d,404,{error:"not found"})}if(z&&b==="POST"){let m=(await ne(v)).enabled!==!1,f=z[1];if(!f)return y(d,400,"Invalid job ID");let w=o.cron.enableJob(f,m);return w?y(d,200,w):y(d,404,{error:"not found"})}if(B&&b==="POST"){let p=await ne(v),m=B[1];if(!m)return y(d,400,"Invalid job ID");let f=await o.cron.runJob(m,!!p.force);return y(d,200,{ok:f})}let re=o.config.gateway.dashboard?.enabled!==!1;if(re&&e){let p=ke.resolve(e,k==="/"?"index.html":k.slice(1));if(!p.startsWith(ke.resolve(e)+ke.sep)&&p!==ke.resolve(e)&&(p=ke.join(e,"index.html")),(!de.existsSync(p)||de.statSync(p).isDirectory())&&(p=ke.join(e,"index.html")),!de.existsSync(p)){d.statusCode=404,d.end("Dashboard assets not found. Run npm run build.");return}d.statusCode=200,d.setHeader("Content-Type",Cl(p)),de.createReadStream(p).pipe(d);return}if(!k.startsWith("/api/")){d.statusCode=404,d.end(re?"Dashboard assets not found. Install the full package or run `npm run build:dashboard`.":"Dashboard is disabled. API endpoints are still available.");return}d.statusCode=404,d.end("Dashboard is disabled. API endpoints are still available.")});return T.listen(t,o.config.gateway.host),o.browserRelay&&(o.browserRelay.attachToServer(T),console.log("[gateway] Browser relay WebSocket endpoint mounted at /ws/browser-relay")),{beginShutdown:()=>{i=!0},port:t,close:()=>(i=!0,new Promise((v,d)=>T.close(b=>{try{r?.close(),s?.close()}catch{}b?d(b):v()})))}}le();import{spawn as Rr}from"node:child_process";import{createWriteStream as _l,existsSync as Gt,lstatSync as Ol,mkdirSync as $l,readdirSync as Ll,rmSync as pn}from"node:fs";import Ar from"node:path";import{pipeline as Dl}from"node:stream/promises";var Ce="0.28.0",Fs="https://github.com/rtk-ai/rtk/releases",Bs=3e4,Er={"darwin-arm64":"rtk-aarch64-apple-darwin.tar.gz","darwin-x64":"rtk-x86_64-apple-darwin.tar.gz","linux-arm64":"rtk-aarch64-unknown-linux-gnu.tar.gz","linux-x64":"rtk-x86_64-unknown-linux-musl.tar.gz","win32-x64":"rtk-x86_64-pc-windows-msvc.zip"},Nl=200,jl=5e3;function Gs(o){return Math.ceil(o.length/4)}function wt(o,e){let t=c=>c.split(".").map(u=>parseInt(u,10)||0),[n=0,r=0,s=0]=t(o),[i=0,a=0,l=0]=t(e);return n!==i?n>=i:r!==a?r>=a:s>=l}var Te=class o{runtime={available:!1,binaryPath:"",version:null};static binaryPath(){let e=process.platform==="win32"?"rtk.exe":"rtk";return Ar.join(fn(),"bin",e)}async resolve(e){if(!e.enabled)return this.runtime={available:!1,binaryPath:"",version:null},this.runtime;let t=o.binaryPath();if(Gt(t)){let n=await this.getVersion(t);if(n&&wt(n,Ce))return this.runtime={available:!0,binaryPath:t,version:n},this.runtime;if(e.autoInstall&&process.env.CI!=="true"){console.error(`[rtk] Binary outdated (${n}, need ${Ce}). Re-downloading...`);try{return await this.install({version:e.version,force:!0})}catch(r){return console.error(`[rtk] Failed to re-download: ${r instanceof Error?r.message:String(r)}`),this.runtime={available:!1,binaryPath:"",version:null},this.runtime}}return this.runtime={available:!1,binaryPath:"",version:null},this.runtime}if(e.autoInstall&&process.env.CI!=="true")try{return await this.install({version:e.version})}catch(n){return console.error(`[rtk] Auto-download failed: ${n instanceof Error?n.message:String(n)}`),this.runtime={available:!1,binaryPath:"",version:null},this.runtime}return this.runtime={available:!1,binaryPath:"",version:null},this.runtime}async install(e){let t=e?.version??"latest",n=`${process.platform}-${process.arch}`,r=Er[n];if(!r)throw new Error(`Unsupported platform: ${n}. Supported platforms: ${Object.keys(Er).join(", ")}`);let s=o.binaryPath(),i=Ar.dirname(s);if(!e?.force&&Gt(s)){let c=await this.getVersion(s);if(c&&wt(c,Ce))return this.runtime={available:!0,binaryPath:s,version:c},this.runtime}let a;if(t==="latest")a=`${Fs}/latest/download/${r}`;else{let c=`v${t.replace(/^v/,"")}`;a=`${Fs}/download/${c}/${r}`}console.error(`[rtk] Downloading from ${a}...`),Gt(i)||$l(i,{recursive:!0});let l=Ar.join(i,`.rtk-download-${Date.now()}.${r.endsWith(".zip")?"zip":"tar.gz"}`);try{if(await this.downloadFile(a,l),r.endsWith(".zip")?await this.extractZip(l,s):await this.extractTarGz(l,s),process.platform!=="win32"){let{chmodSync:u}=await import("node:fs");u(s,493)}let c=await this.getVersion(s);if(!c)throw new Error("Downloaded binary failed version check");return console.error(`[rtk] Installed v${c} to ${s}`),this.runtime={available:!0,binaryPath:s,version:c},this.runtime}finally{Gt(l)&&pn(l,{force:!0})}}async downloadFile(e,t){let{Readable:n}=await import("node:stream"),r=new AbortController,s=setTimeout(()=>r.abort(),Bs);try{let i=await fetch(e,{redirect:"follow",signal:r.signal});if(!i.ok)throw new Error(`Download failed: ${i.status} ${i.statusText}`);if(!i.body)throw new Error("Download failed: No response body");await Dl(n.fromWeb(i.body),_l(t))}catch(i){throw pn(t,{force:!0}),i instanceof Error&&i.name==="AbortError"?new Error(`Download timed out after ${Bs}ms`):i}finally{clearTimeout(s)}}async extractTarGz(e,t){let{renameSync:n}=await import("node:fs"),{mkdtemp:r}=await import("node:fs/promises"),{tmpdir:s}=await import("node:os"),{join:i}=await import("node:path");if(process.platform==="win32")throw new Error("tar.gz extraction on Windows is not supported \u2014 use .zip assets");let a=await r(i(s(),"rtk-extract-"));try{let l=Rr("tar",["-xzf",e,"-C",a],{stdio:["ignore","pipe","pipe"]});await new Promise((u,g)=>{l.on("close",h=>{h===0?u():g(new Error(`tar extraction failed with code ${h}`))}),l.on("error",g)});let c=this.findBinaryInDir(a,"rtk");if(!c)throw new Error("Could not find rtk binary in extracted archive");n(c,t)}finally{pn(a,{recursive:!0,force:!0})}}findBinaryInDir(e,t){let n=process.platform==="win32"?[`${t}.exe`,t]:[t];for(let r of Ll(e)){let s=Ar.join(e,r),i=Ol(s);if(!i.isSymbolicLink()){if(i.isFile()&&n.includes(r))return s;if(i.isDirectory()){let a=this.findBinaryInDir(s,t);if(a)return a}}}return null}async extractZip(e,t){let{renameSync:n}=await import("node:fs"),{mkdtemp:r}=await import("node:fs/promises"),{tmpdir:s}=await import("node:os"),{join:i}=await import("node:path"),a=await r(i(s(),"rtk-extract-"));try{let l=Rr("powershell",["-Command",`Expand-Archive -LiteralPath '${e.replace(/'/g,"''")}' -DestinationPath '${a.replace(/'/g,"''")}' -Force`]);await new Promise((u,g)=>{l.on("close",h=>{h===0?u():g(new Error(`PowerShell extraction failed with code ${h}`))}),l.on("error",g)});let c=this.findBinaryInDir(a,"rtk");if(!c)throw new Error("Could not find rtk binary in extracted archive");n(c,t)}finally{pn(a,{recursive:!0,force:!0})}}async uninstall(){let e=o.binaryPath();Gt(e)&&pn(e,{force:!0}),this.runtime={available:!1,binaryPath:"",version:null}}getRuntime(){return this.runtime}async getStatus(){let e=o.binaryPath();return Gt(e)?{installed:!0,version:await this.getVersion(e),binaryPath:e}:{installed:!1,version:null,binaryPath:e}}async getVersion(e){return new Promise(t=>{let n=Rr(e,["--version"]),r="";n.stdout?.on("data",s=>{r+=s.toString()}),n.on("close",s=>{if(s===0){let i=r.match(/(\d+\.\d+\.\d+)/);t(i?i[1]??null:r.trim()||null)}else t(null)}),n.on("error",()=>t(null))})}async compress(e){if(!this.runtime.available)return{stdout:e.stdout,stderr:e.stderr,compressed:!1,originalTokens:0,compressedTokens:0};if(e.stdout.length<Nl)return{stdout:e.stdout,stderr:e.stderr,compressed:!1,originalTokens:0,compressedTokens:0};let t=Gs(e.stdout);try{let n=await this.runRtkSummary(e.stdout,e.ultraCompact),r=Gs(n);return{stdout:n,stderr:e.stderr,compressed:!0,originalTokens:t,compressedTokens:r}}catch{return{stdout:e.stdout,stderr:e.stderr,compressed:!1,originalTokens:0,compressedTokens:0}}}async runRtkSummary(e,t){return new Promise((n,r)=>{let s=t?["-u","summary"]:["summary"],i=Rr(this.runtime.binaryPath,s),a="",l="",c=setTimeout(()=>{i.kill("SIGKILL"),r(new Error("rtk compression timed out"))},jl);i.stdout?.on("data",u=>{a+=u.toString()}),i.stderr?.on("data",u=>{l+=u.toString()}),i.stdin?.end(e,"utf8"),i.on("close",u=>{clearTimeout(c),u===0?n(a):r(new Error(`rtk exited with code ${u}: ${l}`))}),i.on("error",u=>{clearTimeout(c),r(u)})})}};import{randomUUID as Fl}from"node:crypto";import co,{WebSocketServer as Bl}from"ws";var uo=class{wss=null;extension=null;config;onStatusChange;constructor(e,t){this.config=e,this.onStatusChange=t}handleUpgrade(e,t,n){if(!this.wss){t.destroy();return}let s=new URL(e.url||"/",`http://${e.headers.host||"localhost"}`).searchParams.get("token");if(!this.config.enabled){t.write(`HTTP/1.1 503 Service Unavailable\r
308
308
  \r
309
309
  Browser relay is disabled`),t.destroy();return}if(s!==this.config.authToken){t.write(`HTTP/1.1 401 Unauthorized\r
310
310
  \r
@@ -324,7 +324,7 @@ Invalid auth token`),t.destroy();return}this.wss.handleUpgrade(e,t,n,i=>{this.ha
324
324
  })()`,returnByValue:!0}}),await this.sendCommand("cdp.send",{tabId:e,method:"Input.insertText",params:{text:t}})}async screenshot(e,t="png"){let n=await this.sendCommand("tabs.screenshot",{tabId:e,format:t});return n?.dataUrl??String(n)}async evaluate(e,t){let n=await this.sendCommand("cdp.send",{tabId:e,method:"Runtime.evaluate",params:{expression:t,returnByValue:!0}}),r=n?.result;return r?.type==="string"||r?.type==="number"||r?.type==="boolean"||r?.value!==void 0?r.value:n}async attachTab(e){await this.sendCommand("debugger.attach",{tabId:e}),this.extension?.attachedTabs.add(e),this.notifyStatusChange()}async detachTab(e){await this.sendCommand("debugger.detach",{tabId:e}),this.extension?.attachedTabs.delete(e),this.notifyStatusChange()}close(){this.extension&&(this.extension.ws.close(),this.extension=null),this.wss&&(this.wss.close(),this.wss=null)}};function Us(o,e){let t=o.tools.browserRelay;return!t.enabled||!t.authToken?null:new uo(t,e)}oo();function Gl(o){if(o==="*")return/^.*$/;let e=o.replace(/[.+^${}()|[\]\\]/g,"\\$&").replace(/\*/g,".*");return new RegExp(`^${e}$`)}function Ul(o){if(o==null)return"";if(typeof o!="object")return String(o);try{return JSON.stringify(o)}catch{return""}}var Pr=class{name="RuleBasedToolGuardian";compiledRules=[];constructor(e=[]){this.setRules(e)}setRules(e){this.compiledRules=e.filter(t=>t.enabled).map(t=>{let n;try{n=new RegExp(t.paramPattern)}catch{return null}return{rule:t,toolNameRegex:Gl(t.toolName),paramRegex:n}}).filter(t=>t!==null)}getRules(){return this.compiledRules.map(e=>e.rule)}guard(e){let t=[],{toolName:n,params:r}=e,s=Ul(r);for(let i of this.compiledRules){if(!i.toolNameRegex.test(n))continue;let a=i.paramRegex.exec(s);a&&t.push({id:`rule-${i.rule.id}-${Date.now()}-${t.length}`,ruleId:i.rule.id,category:i.rule.category,severity:i.rule.severity.toUpperCase(),title:i.rule.description,description:i.rule.description,toolName:n,matchedValue:a[0],matchedPattern:i.rule.paramPattern,remediation:i.rule.action==="deny"?"This action is blocked by security policy.":"This pattern has been flagged for review.",guardian:this.name})}return t}matchRules(e,t){return this.guard({toolName:e,params:t})}};un();import Wl from"node:path";import Kl from"node:os";var Ws=["file_path","filepath","filePath","path","directory","dir","filename","target","destination","dest","source","src","output_path","outputPath","input_path","inputPath","log_file","logFile"],Ks=["command","cmd"],Jl=[{pattern:/(?:^|[/"'`\s])\.ssh[/"'`\s]/,category:"SENSITIVE_FILE_ACCESS",severity:"HIGH",title:"SSH directory access detected",description:"Access to ~/.ssh/ directory detected. This contains private keys and SSH configuration.",remediation:"Avoid accessing SSH keys and configuration files directly."},{pattern:/(?:^|[/"'`\s])\.aws[/"'`\s]/,category:"CREDENTIAL_EXPOSURE",severity:"HIGH",title:"AWS credentials directory access detected",description:"Access to ~/.aws/ directory detected. This contains AWS credentials and configuration.",remediation:"Avoid accessing AWS credential files directly."},{pattern:/(?:^|[/"'`\s])\.gnupg[/"'`\s]/,category:"CREDENTIAL_EXPOSURE",severity:"HIGH",title:"GPG directory access detected",description:"Access to ~/.gnupg/ directory detected. This contains PGP private keys.",remediation:"Avoid accessing GPG key material directly."},{pattern:/(?:^|[/"'`\s])\.env(?:[."'\s]|$|\\)/,category:"CREDENTIAL_EXPOSURE",severity:"HIGH",title:"Environment file access detected",description:"Access to .env file detected. This may contain secrets and API keys.",remediation:"Avoid accessing environment files that may contain secrets."},{pattern:/(?:^|[/"'`\s])\.npmrc(?:[."'\s]|$|\\)/,category:"CREDENTIAL_EXPOSURE",severity:"HIGH",title:"NPM configuration access detected",description:"Access to .npmrc file detected. This may contain auth tokens.",remediation:"Avoid accessing npm configuration files that may contain tokens."},{pattern:/(?:^|[/"'`\s])\.netrc(?:[."'\s]|$|\\)/,category:"CREDENTIAL_EXPOSURE",severity:"HIGH",title:"Netrc file access detected",description:"Access to .netrc file detected. This contains authentication credentials.",remediation:"Avoid accessing netrc configuration that may contain credentials."},{pattern:/(?:^|[/"'`\s])\.pypirc(?:[."'\s]|$|\\)/,category:"CREDENTIAL_EXPOSURE",severity:"HIGH",title:"PyPI configuration access detected",description:"Access to .pypirc file detected. This may contain PyPI tokens.",remediation:"Avoid accessing PyPI configuration files."},{pattern:/(?:\/etc\/(?:passwd|shadow|sudoers|crontab|hosts|ssh))/,category:"SENSITIVE_FILE_ACCESS",severity:"HIGH",title:"System configuration file access detected",description:"Access to sensitive system configuration files detected.",remediation:"Avoid accessing system configuration files directly."},{pattern:/(?:\/proc\/(?:self|\d+)\/(?:mem|maps|status|environ|cmdline|fd))/,category:"SENSITIVE_FILE_ACCESS",severity:"HIGH",title:"Process information access detected",description:"Access to sensitive /proc filesystem entries detected.",remediation:"Avoid accessing process memory and information files."}],Js=Kl.homedir();function ql(o){let e=o.trim();return e=e.replace(/^~(?=[/\\])/,Js),e=e.replace(/\$HOME(?=[/\\])/,Js),e}function Hl(o,e){let t=[];for(let n of Ws){let r=o[n];typeof r=="string"&&r.length>0&&t.push(r)}if(/^(?:exec|shell|run_command|execute)$/i.test(e))for(let n of Ks){let r=o[n];typeof r=="string"&&r.length>0&&t.push(r)}for(let[n,r]of Object.entries(o))typeof r=="string"&&!Ws.includes(n)&&!Ks.includes(n)&&/[./\\~$]/.test(r)&&r.length>0&&r.length<4096&&t.push(r);return t}var Ir=class{name="FilePathToolGuardian";workspace;constructor(e){this.workspace=e||process.cwd()}setWorkspace(e){this.workspace=e}guard(e){let t=[],{toolName:n,params:r}=e;if(!r||typeof r!="object"||Array.isArray(r))return t;let s=Hl(r,n);for(let i of s){let a=ql(i),l=this.checkPathTraversal(i,a,n);l&&t.push(l);let c=this.checkSensitivePaths(i,a,n);t.push(...c);let u=this.checkWorkspaceEscape(a,n);u&&t.push(u)}return t}checkPathTraversal(e,t,n){return/\.\.\//.test(e)||/\.\.\\/.test(e)?{id:`file-traversal-${Date.now()}-${Math.random().toString(36).slice(2,8)}`,ruleId:"file-path-traversal",category:"PATH_TRAVERSAL",severity:"HIGH",title:"Path traversal detected",description:`Path traversal pattern '../' detected in path: '${this.truncateForDisplay(e)}'. This could allow access to files outside the intended directory.`,toolName:n,matchedValue:e,matchedPattern:"\\.\\./",remediation:"Avoid using relative paths with '../' sequences.",guardian:this.name}:/%00|%0[dD]/.test(e)?{id:`null-byte-${Date.now()}-${Math.random().toString(36).slice(2,8)}`,ruleId:"file-null-byte",category:"PATH_TRAVERSAL",severity:"HIGH",title:"Null byte injection detected",description:`Null byte injection pattern detected in path: '${this.truncateForDisplay(e)}'. This could bypass path validation.`,toolName:n,matchedValue:e,matchedPattern:"%00|%0[dD]",remediation:"Do not include null bytes in path strings.",guardian:this.name}:null}checkSensitivePaths(e,t,n){let r=[],s=new Set([e,t]);for(let i of s)for(let a of Jl)a.pattern.test(i)&&r.push({id:`sensitive-path-${Date.now()}-${Math.random().toString(36).slice(2,8)}`,ruleId:`sensitive-path-${a.title.replace(/\s+/g,"-").toLowerCase()}`,category:a.category,severity:a.severity,title:a.title,description:a.description,toolName:n,matchedValue:this.truncateForDisplay(i),matchedPattern:a.pattern.source,remediation:a.remediation,guardian:this.name});return r}checkWorkspaceEscape(e,t){if(!Wl.isAbsolute(e))return null;try{je(e,this.workspace)}catch{return{id:`workspace-escape-${Date.now()}-${Math.random().toString(36).slice(2,8)}`,ruleId:"file-workspace-escape",category:"PATH_TRAVERSAL",severity:"MEDIUM",title:"Workspace escape detected",description:`Absolute path '${this.truncateForDisplay(e)}' is outside the configured workspace '${this.workspace}'.`,toolName:t,matchedValue:this.truncateForDisplay(e),remediation:"Use paths within the configured workspace directory.",guardian:this.name}}return null}truncateForDisplay(e,t=200){return e.length<=t?e:e.slice(0,t)+"\u2026"}};un();import go from"node:fs";import qs from"node:path";var zl=new Set([".png",".jpg",".jpeg",".gif",".bmp",".ico",".svg",".webp",".woff",".woff2",".ttf",".otf",".eot",".pdf",".zip",".gz",".tar",".7z",".rar",".bz2",".xz",".mp3",".mp4",".avi",".mov",".wmv",".flv",".mkv",".exe",".dll",".so",".dylib",".bin",".dat"]),Vl=8192,Xl=.01;function Yl(o){let e=Math.min(o.length,Vl);if(e===0)return!1;let t=0;for(let n=0;n<e;n++)o[n]===0&&t++;return t/e>=Xl}var tt=class{analyzers;constructor(e=[]){this.analyzers=e}scanSkill(e,t,n){let r=n?.maxFileCount??1e3,s=n?.maxFileSizeBytes??5242880,i={scannedFiles:0,skippedFiles:0,symlinksSkipped:0,oversizedFiles:0},a=[],l=this.walkDirectory(e,i);for(let g of l){if(i.scannedFiles>=r){i.skippedFiles++;continue}if(zl.has(g.ext)){i.skippedFiles++;continue}if(g.size>s){i.oversizedFiles++;continue}let h;try{h=go.readFileSync(g.absPath)}catch{i.skippedFiles++;continue}if(Yl(h)){i.skippedFiles++;continue}let T=h.toString("utf8"),v={filePath:g.absPath,extension:g.ext,size:g.size,content:T};for(let d of this.analyzers){let b=d.analyze(v);a.push(...b)}i.scannedFiles++}let c=Ql(a),u=!a.some(g=>g.severity==="CRITICAL"||g.severity==="HIGH");return{skillName:t,findings:a,isSafe:u,maxSeverity:c,stats:i}}walkDirectory(e,t){let n=[],r;try{r=go.readdirSync(e,{withFileTypes:!0})}catch{return n}for(let s of r){let i=qs.join(e,s.name);if(s.isSymbolicLink()){t.symlinksSkipped++;continue}if(s.isDirectory()){let a=this.walkDirectory(i,t);n.push(...a);continue}if(s.isFile())try{let a=go.lstatSync(i),l=qs.extname(s.name).toLowerCase();n.push({absPath:i,ext:l,size:a.size})}catch{t.skippedFiles++}}return n}};function Ql(o){if(o.length===0)return"SAFE";let e={CRITICAL:5,HIGH:4,MEDIUM:3,LOW:2,INFO:1,SAFE:0},t=0;for(let n of o){let r=e[n.severity]??0;r>t&&(t=r)}for(let[n,r]of Object.entries(e))if(r===t)return n;return"SAFE"}un();le();import Zl from"node:fs";var ec=new Set([".png",".jpg",".jpeg",".gif",".bmp",".ico",".svg",".webp",".woff",".woff2",".ttf",".otf",".eot",".pdf",".zip",".gz",".tar",".7z",".rar",".bz2",".xz",".mp3",".mp4",".avi",".mov",".wmv",".flv",".mkv",".exe",".dll",".so",".dylib",".bin",".dat"]),tc=8192,nc=.01,nt=class{name="PatternAnalyzer";signatures=null;compiledPatterns=new Map;loadSignatures(){if(this.signatures)return this.signatures;try{let e=ze("security","skill-scanner","rules","signatures.json");if(!e)return this.signatures=[],[];let t=Zl.readFileSync(e,"utf8"),n=JSON.parse(t);return this.signatures=n,n}catch{return this.signatures=[],[]}}compilePattern(e,t){let n=this.compiledPatterns.get(e);if(n)return n;try{let r=new RegExp(t,"gm");return this.compiledPatterns.set(e,r),r}catch{return null}}isBinaryContent(e){let t=Math.min(e.length,tc);if(t===0)return!1;let n=0;for(let r=0;r<t;r++)e.charCodeAt(r)===0&&n++;return n/t>=nc}isSkippedExtension(e){return ec.has(e)}analyze(e){let{extension:t,content:n}=e,r=[];if(this.isSkippedExtension(t)||this.isBinaryContent(n))return r;let s=this.loadSignatures();for(let i of s){if(!i.fileTypes.includes(t))continue;let a=this.compilePattern(i.id,i.pattern);if(!a)continue;a.lastIndex=0,a.exec(n)&&r.push({id:i.id,category:dn[i.category]??"COMMAND_INJECTION",severity:cn[i.severity]??"MEDIUM",pattern:i.pattern,fileTypes:i.fileTypes,title:i.title,description:i.description,remediation:i.remediation})}return r}};async function Hs(o){let e=structuredClone(o?.config??M()),t=o?.port??e.gateway.port??6767;e.gateway.port=t;let n=X(e.agents.defaults.workspace);lt(n,!0);let r=e.gateway.host,s=r==="127.0.0.1"||r==="localhost"||r==="::1",i=e.gateway.dashboard?.enabled!==!1,a=e.security?.auth?.enabled===!0;if(!s&&i&&!a)throw new Error("Dashboard is exposed on a non-loopback address ("+r+`) but authentication is not configured. Either:
325
325
  1. Set security.auth.enabled = true and configure a PIN
326
326
  2. Set gateway.host = 127.0.0.1 (loopback only)
327
- 3. Set gateway.dashboard.enabled = false (API-only mode)`);let l=new ut,c=o?.provider??_e(e),u=new Qe(n),g=De(),h=new Bt(n,g),T=pr(e.tools.exec.timeout),v=an({target:"scheduled-job",timeoutMs:T}),d=an({target:"background-job",timeoutMs:T}),{cron:b,heartbeat:$,lifecycle:k}=Je({cron:{dataDir:g,onJob:async(I,j)=>{let q=await v.run({payload:{message:I.payload.message,session:`cron:${I.id}`,channel:I.payload.channel??"cli",chatId:I.payload.to??"direct"},cwd:process.cwd(),signal:j?.signal});if(I.payload.deliver&&I.payload.to){let re=I.payload.channel??"cli",p=I.payload.to;await l.publishOutbound({channel:re,chatId:p,content:q});try{h.record({jobId:I.id,jobName:I.name,sessionKey:`cron:${I.id}`,channel:re,recipient:p,content:q})}catch(m){console.warn(`[dashboard] Failed to record inbox delivery for cron job ${I.id}: ${m instanceof Error?m.message:String(m)}`)}}return q}},heartbeat:{workspace:n,provider:c,model:e.agents.defaults.model,onExecute:async(I,j)=>{let re=u.listSessions().find(f=>(f.key??"").includes(":"))?.key??"cli:direct",[p,m]=re.split(/:(.*)/s,2);return d.run({payload:{message:I,session:"heartbeat",channel:p||"cli",chatId:m||"direct"},cwd:process.cwd(),signal:j?.signal})},onNotify:async I=>{let q=u.listSessions().find(m=>(m.key??"").includes(":"))?.key??"",[re,p]=q?q.split(/:(.*)/s,2):["cli","direct"];re!=="cli"&&re&&await l.publishOutbound({channel:re,chatId:p??"direct",content:I})},intervalS:e.gateway.heartbeat.intervalS,enabled:e.gateway.heartbeat.enabled}});if(!$)throw new Error("Builtin heartbeat job registration is missing");let U,L;e.security.enabled&&(e.security.toolGuard.enabled&&(U=gn.getInstance(e),U.registerGuardian(new Pr(U.getRules())),U.registerGuardian(new Ir(n)),console.log("[security] Tool guard engine initialized with guardians")),e.security.skillScanner.enabled&&(L=new tt([new nt]),console.log("[security] Skill scanner initialized")));let N=new Te,z=await N.resolve(e.tools.rtk);z.available?console.log(`rtk ${z.version} \u2014 token compression enabled`):e.tools.rtk.enabled&&(e.tools.rtk.autoInstall&&process.env.CI==="true"?console.log("rtk not available \u2014 auto-install skipped in CI (run `everclaw rtk install` in Dockerfile)"):e.tools.rtk.autoInstall?console.log("rtk not available \u2014 auto-install failed; token compression disabled (run `everclaw rtk install` to retry)"):console.log("rtk not available \u2014 token compression disabled (run `everclaw rtk install` to enable)"));let F=null;if(e.tools.browserRelay.enabled&&e.tools.browserRelay.authToken){let I=Us(e,j=>{j.connected&&console.log(`[browser-relay] Extension connected, ${j.attachedTabs.length} tabs attached`)});I&&(F=I,console.log("[browser-relay] WebSocket endpoint ready at /ws/browser-relay"))}let ae=new Nt({bus:l,provider:c,workspace:n,sessionManager:u,model:e.agents.defaults.model,temperature:e.agents.defaults.temperature,maxTokens:e.agents.defaults.maxTokens,maxIterations:e.agents.defaults.maxToolIterations,memoryWindow:e.agents.defaults.memoryWindow,braveApiKey:e.tools.web.search.apiKey||null,execConfig:e.tools.exec,cronService:b,restrictToWorkspace:e.tools.restrictToWorkspace,channelsConfig:e.channels,lifecycle:k,loadConfig:M,rtkConfig:e.tools.rtk,rtkService:N,...U?{guardEngine:U}:{},...e.security.skillScanner.enabled?{skillScannerConfig:e.security.skillScanner}:{},...L?{skillScanner:L}:{},...F?{browserRelay:F}:{},...e.tools.chromeSession?.enabled?{chromeSessionConfig:e.tools.chromeSession}:{}}),J=new yr(e,l,k),Z=js({agent:ae,cron:b,config:e,dataDir:g,port:t,sessionManager:u,sessionKey:o?.sessionKey??"default:everclaw",inboxService:h,workspacePath:n,channelManager:J,...F?{browserRelay:F}:{}});await b.start(),await $.start();let A=ae.run();return await J.startAll(),{config:e,workspace:n,port:Z.port,loop:ae,heartbeat:$,cron:b,channels:J,dashboard:Z,enabledChannels:J.enabledChannels,runPromise:A,browserRelay:F}}async function mo(o){o.dashboard.beginShutdown?.(),o.loop.beginShutdown(),o.heartbeat.stop(),o.cron.stop();let e=await o.loop.shutdown();return await o.channels.stopAll(),_t.getInstance().stopAll(),await o.dashboard.close(),e}import G from"chalk";import{Command as rc}from"commander";Ne();var K={SUCCESS:0,GENERAL_ERROR:1,CONNECTIVITY_ERROR:2,SECURITY_ERROR:3,PROCESS_CONFLICT:4};function zs(){let o=new rc("rtk").description("Manage rtk token compression binary");return o.addHelpText("after",`
327
+ 3. Set gateway.dashboard.enabled = false (API-only mode)`);let l=new ut,c=o?.provider??_e(e),u=new Qe(n),g=De(),h=new Bt(n,g),T=pr(e.tools.exec.timeout),v=an({target:"scheduled-job",timeoutMs:T}),d=an({target:"background-job",timeoutMs:T}),{cron:b,heartbeat:$,lifecycle:k}=Je({cron:{dataDir:g,onJob:async(I,F)=>{let q=await v.run({payload:{message:I.payload.message,session:`cron:${I.id}`,channel:I.payload.channel??"cli",chatId:I.payload.to??"direct"},cwd:process.cwd(),signal:F?.signal});if(I.payload.deliver&&I.payload.to){let re=I.payload.channel??"cli",p=I.payload.to;await l.publishOutbound({channel:re,chatId:p,content:q});try{h.record({jobId:I.id,jobName:I.name,sessionKey:`cron:${I.id}`,channel:re,recipient:p,content:q})}catch(m){console.warn(`[dashboard] Failed to record inbox delivery for cron job ${I.id}: ${m instanceof Error?m.message:String(m)}`)}}return q}},heartbeat:{workspace:n,provider:c,model:e.agents.defaults.model,onExecute:async(I,F)=>{let re=u.listSessions().find(f=>(f.key??"").includes(":"))?.key??"cli:direct",[p,m]=re.split(/:(.*)/s,2);return d.run({payload:{message:I,session:"heartbeat",channel:p||"cli",chatId:m||"direct"},cwd:process.cwd(),signal:F?.signal})},onNotify:async I=>{let q=u.listSessions().find(m=>(m.key??"").includes(":"))?.key??"",[re,p]=q?q.split(/:(.*)/s,2):["cli","direct"];re!=="cli"&&re&&await l.publishOutbound({channel:re,chatId:p??"direct",content:I})},intervalS:e.gateway.heartbeat.intervalS,enabled:e.gateway.heartbeat.enabled}});if(!$)throw new Error("Builtin heartbeat job registration is missing");let U,L;e.security.enabled&&(e.security.toolGuard.enabled&&(U=gn.getInstance(e),U.registerGuardian(new Pr(U.getRules())),U.registerGuardian(new Ir(n)),console.log("[security] Tool guard engine initialized with guardians")),e.security.skillScanner.enabled&&(L=new tt([new nt]),console.log("[security] Skill scanner initialized")));let N=new Te,z=await N.resolve(e.tools.rtk);z.available?console.log(`rtk ${z.version} \u2014 token compression enabled`):e.tools.rtk.enabled&&(e.tools.rtk.autoInstall&&process.env.CI==="true"?console.log("rtk not available \u2014 auto-install skipped in CI (run `everclaw rtk install` in Dockerfile)"):e.tools.rtk.autoInstall?console.log("rtk not available \u2014 auto-install failed; token compression disabled (run `everclaw rtk install` to retry)"):console.log("rtk not available \u2014 token compression disabled (run `everclaw rtk install` to enable)"));let B=null;if(e.tools.browserRelay.enabled&&e.tools.browserRelay.authToken){let I=Us(e,F=>{F.connected&&console.log(`[browser-relay] Extension connected, ${F.attachedTabs.length} tabs attached`)});I&&(B=I,console.log("[browser-relay] WebSocket endpoint ready at /ws/browser-relay"))}let ae=new Nt({bus:l,provider:c,workspace:n,sessionManager:u,model:e.agents.defaults.model,temperature:e.agents.defaults.temperature,maxTokens:e.agents.defaults.maxTokens,maxIterations:e.agents.defaults.maxToolIterations,memoryWindow:e.agents.defaults.memoryWindow,braveApiKey:e.tools.web.search.apiKey||null,execConfig:e.tools.exec,cronService:b,restrictToWorkspace:e.tools.restrictToWorkspace,channelsConfig:e.channels,lifecycle:k,loadConfig:M,rtkConfig:e.tools.rtk,rtkService:N,...U?{guardEngine:U}:{},...e.security.skillScanner.enabled?{skillScannerConfig:e.security.skillScanner}:{},...L?{skillScanner:L}:{},...B?{browserRelay:B}:{},...e.tools.chromeSession?.enabled?{chromeSessionConfig:e.tools.chromeSession}:{}}),J=new yr(e,l,k),Z=js({agent:ae,cron:b,config:e,dataDir:g,port:t,sessionManager:u,sessionKey:o?.sessionKey??"default:everclaw",inboxService:h,workspacePath:n,channelManager:J,...B?{browserRelay:B}:{}});await b.start(),await $.start();let A=ae.run();return await J.startAll(),{config:e,workspace:n,port:Z.port,loop:ae,heartbeat:$,cron:b,channels:J,dashboard:Z,enabledChannels:J.enabledChannels,runPromise:A,browserRelay:B}}async function mo(o){o.dashboard.beginShutdown?.(),o.loop.beginShutdown(),o.heartbeat.stop(),o.cron.stop();let e=await o.loop.shutdown();return await o.channels.stopAll(),_t.getInstance().stopAll(),await o.dashboard.close(),e}import G from"chalk";import{Command as rc}from"commander";Ne();var K={SUCCESS:0,GENERAL_ERROR:1,CONNECTIVITY_ERROR:2,SECURITY_ERROR:3,PROCESS_CONFLICT:4};function zs(){let o=new rc("rtk").description("Manage rtk token compression binary");return o.addHelpText("after",`
328
328
  Examples:
329
329
  everclaw rtk install Install the latest rtk binary
330
330
  everclaw rtk update Update to the latest version
@@ -333,14 +333,16 @@ rtk v${n.version} installed to ${n.binaryPath}`)),console.log(G.gray("Token comp
333
333
  RTK Token Compression
334
334
  `)),t.installed&&t.version?(console.log(` Status: ${G.green("Available")} (v${t.version})`),console.log(` Binary: ${t.binaryPath}`),wt(t.version,Ce)||(console.log(G.yellow(` Warning: Version ${t.version} is below minimum ${Ce}`)),console.log(G.gray(` Run ${G.cyan("everclaw rtk install --force")} to update`)))):t.installed?(console.log(` Status: ${G.yellow("Installed but broken")}`),console.log(` Binary: ${t.binaryPath}`),console.log(G.gray(` Run ${G.cyan("everclaw rtk install --force")} to reinstall`))):(console.log(` Status: ${G.gray("Not installed")}`),console.log(G.gray(` Fix: Run ${G.cyan("everclaw rtk install")} or set tools.rtk.autoInstall=true`))),console.log(` Enabled: ${n.tools.rtk.enabled?G.green("yes"):G.gray("no")}`),console.log(G.gray(`
335
335
  Minimum version: ${Ce}`)),console.log(G.gray(` Supported platforms: ${Object.keys(Er).join(", ")}`))}),o.command("update").description("Update rtk to the latest version").action(async()=>{let e=new Te,t=await e.getStatus(),n=t.installed&&t.version?t.version:null;console.log(n?G.cyan(`Current: v${n}`):G.gray("rtk is not installed."));try{console.log(G.gray("Fetching latest version..."));let r=await e.install({version:"latest",force:!0});n&&r.version===n?console.log(G.green(`Already at latest version (v${r.version})`)):console.log(G.green(`
336
- rtk v${r.version} installed to ${r.binaryPath}`))}catch(r){console.error(G.red(`Failed to update rtk: ${r instanceof Error?r.message:String(r)}`)),process.exitCode=K.CONNECTIVITY_ERROR}}),o.command("enable").description("Enable rtk token compression in config").action(()=>{let e=M();if(e.tools.rtk.enabled){console.log(G.gray("RTK token compression is already enabled."));return}e.tools.rtk.enabled=!0,oe(e),console.log(G.green("RTK token compression enabled.")),console.log(G.gray("Restart the gateway for changes to take effect."))}),o.command("disable").description("Disable rtk token compression in config").action(()=>{let e=M();if(!e.tools.rtk.enabled){console.log(G.gray("RTK token compression is already disabled."));return}e.tools.rtk.enabled=!1,oe(e),console.log(G.yellow("RTK token compression disabled.")),console.log(G.gray("Restart the gateway for changes to take effect.")),console.log(G.gray("The binary remains installed \u2014 run `everclaw rtk uninstall` to remove it."))}),o}Tt();Ne();import{spawn as oc}from"node:child_process";import B from"chalk";import{Command as sc,Option as ic}from"commander";async function ac(){let o=Ee();if(!o)return!0;if(!Ae(o.pid))return Pe(),!0;console.log(B.cyan(`Stopping gateway (PID ${o.pid})...`));try{process.kill(o.pid,"SIGTERM")}catch(t){return console.error(B.red(`Failed to send SIGTERM to PID ${o.pid}: ${String(t)}`)),!1}if(!await Br(o.pid,1e4)){console.log(B.yellow("Gateway did not exit within 10s, sending SIGKILL..."));try{process.kill(o.pid,"SIGKILL")}catch{}}return Pe(),console.log(B.green("Gateway stopped.")),!0}async function Vs(o){let e=Ee();if(e&&Ae(e.pid)){console.error(B.red(`Gateway is already running (PID ${e.pid}, port ${e.port}).`)),console.error(B.gray('Use "everclaw gateway restart" to restart it.')),process.exitCode=K.PROCESS_CONFLICT;return}e&&Pe();let t=M(),n=fo(o.port,t.gateway.port),r=["gateway","start","--port",String(n)];o.host&&r.push("--host",o.host),r.push("--_foreground");let s=oc(process.execPath,[process.argv[1],...r],{detached:!0,stdio:"ignore",env:{...process.env}});if(!s.pid){console.error(B.red("Failed to spawn gateway process.")),process.exitCode=K.GENERAL_ERROR;return}if(s.unref(),Fr({pid:s.pid,port:n,startedAt:new Date().toISOString()}),await new Promise(i=>setTimeout(i,1500)),!Ae(s.pid)){console.error(B.red("Gateway process exited immediately. Check logs for errors.")),Pe(),process.exitCode=K.GENERAL_ERROR;return}console.log(B.green(`Gateway started in background (PID ${s.pid}, port ${n}).`)),console.log(B.gray(`Dashboard: http://localhost:${n}/chat`)),console.log(B.gray("Use `everclaw gateway status` to check, `everclaw gateway stop` to stop."))}async function po(o){let e=M(),t={};o.host&&(t.gatewayHost=o.host),o.port&&(t.gatewayPort=fo(o.port,e.gateway.port));let n=Kt(e,process.env,t),r=n.gateway.port,s=Ee();if(s&&Ae(s.pid)){console.error(B.red(`Gateway is already running (PID ${s.pid}, port ${s.port}).`)),console.error(B.gray('Use "everclaw gateway restart" to restart it.')),process.exitCode=K.PROCESS_CONFLICT;return}s&&Pe();let i;try{i=await Hs({config:n,port:r,sessionKey:"default:everclaw"})}catch(g){console.log(B.red(String(g))),process.exitCode=K.GENERAL_ERROR;return}Fr({pid:process.pid,port:i.port,startedAt:new Date().toISOString()}),console.log(B.cyan(`Starting everclaw gateway on port ${i.port}...`)),i.enabledChannels.length?console.log(B.green(`Channels enabled: ${i.enabledChannels.join(", ")}`)):console.log(B.yellow("No channels enabled. Gateway will stay idle until channels are configured.")),console.log(B.green(`Dashboard: http://localhost:${i.port}/chat`)),console.log(B.gray("Gateway running. Press Ctrl+C to stop."));let a=null,l=async g=>a||(console.log(B.yellow(`
337
- Received ${g}. Shutting down gateway...`)),Pe(process.pid),a=mo(i).then(h=>{h>0&&console.log(B.gray(`Cancelled ${h} task(s) during shutdown.`))}).catch(h=>{process.exitCode=1,console.log(B.red(`Gateway shutdown failed: ${String(h)}`))}),a),c=()=>{l("SIGINT")},u=()=>{l("SIGTERM")};process.once("SIGINT",c),process.once("SIGTERM",u);try{await i.runPromise,a&&await a}finally{Pe(process.pid),process.off("SIGINT",c),process.off("SIGTERM",u)}}function Xs(){let o=new sc("gateway").description("Manage the everclaw gateway");return o.addHelpText("after",`
336
+ rtk v${r.version} installed to ${r.binaryPath}`))}catch(r){console.error(G.red(`Failed to update rtk: ${r instanceof Error?r.message:String(r)}`)),process.exitCode=K.CONNECTIVITY_ERROR}}),o.command("enable").description("Enable rtk token compression in config").action(()=>{let e=M();if(e.tools.rtk.enabled){console.log(G.gray("RTK token compression is already enabled."));return}e.tools.rtk.enabled=!0,oe(e),console.log(G.green("RTK token compression enabled.")),console.log(G.gray("Restart the gateway for changes to take effect."))}),o.command("disable").description("Disable rtk token compression in config").action(()=>{let e=M();if(!e.tools.rtk.enabled){console.log(G.gray("RTK token compression is already disabled."));return}e.tools.rtk.enabled=!1,oe(e),console.log(G.yellow("RTK token compression disabled.")),console.log(G.gray("Restart the gateway for changes to take effect.")),console.log(G.gray("The binary remains installed \u2014 run `everclaw rtk uninstall` to remove it."))}),o}Tt();Ne();import{spawn as oc}from"node:child_process";import sc from"node:fs";import ic from"node:path";import j from"chalk";import{Command as ac,Option as lc}from"commander";function cc(){let o=process.argv[1];if(o){let e=ic.resolve(o);if(sc.existsSync(e))return e}return"everclaw"}async function dc(){let o=Ee();if(!o)return!0;if(!Ae(o.pid))return Pe(),!0;console.log(j.cyan(`Stopping gateway (PID ${o.pid})...`));try{process.kill(o.pid,"SIGTERM")}catch(t){return console.error(j.red(`Failed to send SIGTERM to PID ${o.pid}: ${String(t)}`)),!1}if(!await Br(o.pid,1e4)){console.log(j.yellow("Gateway did not exit within 10s, sending SIGKILL..."));try{process.kill(o.pid,"SIGKILL")}catch{}}return Pe(),console.log(j.green("Gateway stopped.")),!0}async function Vs(o){let e=Ee();if(e&&Ae(e.pid)){console.error(j.red(`Gateway is already running (PID ${e.pid}, port ${e.port}).`)),console.error(j.gray('Use "everclaw gateway restart" to restart it.')),process.exitCode=K.PROCESS_CONFLICT;return}e&&Pe();let t=M(),n=fo(o.port,t.gateway.port),r=cc(),s=["gateway","start","--port",String(n)];o.host&&s.push("--host",o.host),s.push("--_foreground");let i="",a=oc(r,s,{detached:!0,stdio:["ignore","ignore","pipe"],env:{...process.env}});if(!a.pid){console.error(j.red("Failed to spawn gateway process.")),process.exitCode=K.GENERAL_ERROR;return}if(a.stderr?.on("data",l=>{i+=l.toString("utf8"),i.length>4096&&(i=i.slice(-4096))}),setTimeout(()=>{a.stderr?.destroy()},3e3).unref(),a.unref(),Fr({pid:a.pid,port:n,startedAt:new Date().toISOString()}),await new Promise(l=>setTimeout(l,1500)),!Ae(a.pid)){Pe(),console.error(j.red("Gateway process exited immediately.")),i.trim()?console.error(j.gray(i.trim().split(`
337
+ `).map(l=>` ${l}`).join(`
338
+ `))):console.error(j.gray("No error output captured. Try running with -f for details.")),process.exitCode=K.GENERAL_ERROR;return}console.log(j.green(`Gateway started in background (PID ${a.pid}, port ${n}).`)),console.log(j.gray(`Dashboard: http://localhost:${n}/chat`)),console.log(j.gray("Use `everclaw gateway status` to check, `everclaw gateway stop` to stop."))}async function po(o){let e=M(),t={};o.host&&(t.gatewayHost=o.host),o.port&&(t.gatewayPort=fo(o.port,e.gateway.port));let n=Kt(e,process.env,t),r=n.gateway.port,s=Ee();if(s&&s.pid!==process.pid&&Ae(s.pid)){console.error(j.red(`Gateway is already running (PID ${s.pid}, port ${s.port}).`)),console.error(j.gray('Use "everclaw gateway restart" to restart it.')),process.exitCode=K.PROCESS_CONFLICT;return}s&&s.pid!==process.pid&&Pe();let i;try{i=await Hs({config:n,port:r,sessionKey:"default:everclaw"})}catch(g){console.log(j.red(String(g))),process.exitCode=K.GENERAL_ERROR;return}Fr({pid:process.pid,port:i.port,startedAt:new Date().toISOString()}),console.log(j.cyan(`Starting everclaw gateway on port ${i.port}...`)),i.enabledChannels.length?console.log(j.green(`Channels enabled: ${i.enabledChannels.join(", ")}`)):console.log(j.yellow("No channels enabled. Gateway will stay idle until channels are configured.")),console.log(j.green(`Dashboard: http://localhost:${i.port}/chat`)),console.log(j.gray("Gateway running. Press Ctrl+C to stop."));let a=null,l=async g=>a||(console.log(j.yellow(`
339
+ Received ${g}. Shutting down gateway...`)),Pe(process.pid),a=mo(i).then(h=>{h>0&&console.log(j.gray(`Cancelled ${h} task(s) during shutdown.`))}).catch(h=>{process.exitCode=1,console.log(j.red(`Gateway shutdown failed: ${String(h)}`))}),a),c=()=>{l("SIGINT")},u=()=>{l("SIGTERM")};process.once("SIGINT",c),process.once("SIGTERM",u);try{await i.runPromise,a&&await a}finally{Pe(process.pid),process.off("SIGINT",c),process.off("SIGTERM",u)}}function Xs(){let o=new ac("gateway").description("Manage the everclaw gateway");return o.addHelpText("after",`
338
340
  Examples:
339
341
  everclaw gateway Start the gateway in background (default)
340
342
  everclaw gateway start -f Start in foreground
341
343
  everclaw gateway status Check if gateway is running
342
344
  everclaw gateway restart Restart the gateway
343
- everclaw gateway stop Stop a running gateway`),o.command("start",{isDefault:!0}).description("Start the everclaw gateway in background (default when no subcommand given)").option("-p, --port <port>","Gateway port",String(fe.gateway.port)).option("-H, --host <host>","Gateway bind address").option("-f, --foreground","Run in the foreground instead of background").addOption(new ic("--_foreground").hideHelp()).action(async e=>{if(e._foreground){await po({port:e.port,host:e.host});return}if(e.foreground){await po({port:e.port,host:e.host});return}await Vs({port:e.port,host:e.host})}),o.command("stop").description("Stop a running gateway").action(async()=>{let e=Ee();if(!e){console.log(B.yellow("No gateway PID file found. Is the gateway running?")),process.exitCode=K.GENERAL_ERROR;return}if(!Ae(e.pid)){console.log(B.yellow(`Gateway process (PID ${e.pid}) is not running. Cleaning up stale PID file.`)),Pe();return}try{process.kill(e.pid,"SIGTERM")}catch(n){console.error(B.red(`Failed to send SIGTERM to PID ${e.pid}: ${String(n)}`)),process.exitCode=K.GENERAL_ERROR;return}if(await Br(e.pid,1e4))Pe(),console.log(B.green("Gateway stopped."));else{console.log(B.yellow("Gateway did not exit within 10s, sending SIGKILL..."));try{process.kill(e.pid,"SIGKILL")}catch{}Pe(),console.log(B.green("Gateway killed."))}}),o.command("restart").description("Restart the gateway (stop then start)").option("-p, --port <port>","Gateway port",String(fe.gateway.port)).option("-H, --host <host>","Gateway bind address").option("-f, --foreground","Run in the foreground instead of background").option("--force","Start even if stop fails",!1).action(async e=>{if(!await ac()){if(!e.force){console.error(B.red("Failed to stop gateway. Use --force to start anyway.")),process.exitCode=K.GENERAL_ERROR;return}console.log(B.yellow("Warning: stop did not complete cleanly. Starting anyway (--force)."))}console.log(B.cyan("Starting gateway...")),e.foreground?await po({port:e.port,host:e.host}):await Vs({port:e.port,host:e.host})}),o.command("status").description("Show gateway process status").action(async()=>{let e=Ee();if(!e){console.log(B.yellow("Gateway is not running (no PID file found)."));return}if(!Ae(e.pid)){console.log(B.yellow(`Gateway process (PID ${e.pid}) is not running. Stale PID file.`));return}let t=dt(e.startedAt);console.log(B.green("Gateway is running")),console.log(` PID: ${e.pid}`),console.log(` Port: ${e.port}`),console.log(` Uptime: ${t}`),console.log(` Started: ${e.startedAt}`)}),o}import H from"chalk";import{Command as lc}from"commander";import rt from"node:fs";import ot from"node:path";Ne();$e();function Ys(){let o=new lc("skills").description("Manage skills");return o.addHelpText("after",`
345
+ everclaw gateway stop Stop a running gateway`),o.command("start",{isDefault:!0}).description("Start the everclaw gateway in background (default when no subcommand given)").option("-p, --port <port>","Gateway port",String(fe.gateway.port)).option("-H, --host <host>","Gateway bind address").option("-f, --foreground","Run in the foreground instead of background").addOption(new lc("--_foreground").hideHelp()).action(async e=>{if(e._foreground){await po({port:e.port,host:e.host});return}if(e.foreground){await po({port:e.port,host:e.host});return}await Vs({port:e.port,host:e.host})}),o.command("stop").description("Stop a running gateway").action(async()=>{let e=Ee();if(!e){console.log(j.yellow("No gateway PID file found. Is the gateway running?")),process.exitCode=K.GENERAL_ERROR;return}if(!Ae(e.pid)){console.log(j.yellow(`Gateway process (PID ${e.pid}) is not running. Cleaning up stale PID file.`)),Pe();return}try{process.kill(e.pid,"SIGTERM")}catch(n){console.error(j.red(`Failed to send SIGTERM to PID ${e.pid}: ${String(n)}`)),process.exitCode=K.GENERAL_ERROR;return}if(await Br(e.pid,1e4))Pe(),console.log(j.green("Gateway stopped."));else{console.log(j.yellow("Gateway did not exit within 10s, sending SIGKILL..."));try{process.kill(e.pid,"SIGKILL")}catch{}Pe(),console.log(j.green("Gateway killed."))}}),o.command("restart").description("Restart the gateway (stop then start)").option("-p, --port <port>","Gateway port",String(fe.gateway.port)).option("-H, --host <host>","Gateway bind address").option("-f, --foreground","Run in the foreground instead of background").option("--force","Start even if stop fails",!1).action(async e=>{if(!await dc()){if(!e.force){console.error(j.red("Failed to stop gateway. Use --force to start anyway.")),process.exitCode=K.GENERAL_ERROR;return}console.log(j.yellow("Warning: stop did not complete cleanly. Starting anyway (--force)."))}console.log(j.cyan("Starting gateway...")),e.foreground?await po({port:e.port,host:e.host}):await Vs({port:e.port,host:e.host})}),o.command("status").description("Show gateway process status").action(async()=>{let e=Ee();if(!e){console.log(j.yellow("Gateway is not running (no PID file found)."));return}if(!Ae(e.pid)){console.log(j.yellow(`Gateway process (PID ${e.pid}) is not running. Stale PID file.`));return}let t=dt(e.startedAt);console.log(j.green("Gateway is running")),console.log(` PID: ${e.pid}`),console.log(` Port: ${e.port}`),console.log(` Uptime: ${t}`),console.log(` Started: ${e.startedAt}`)}),o}import H from"chalk";import{Command as uc}from"commander";import rt from"node:fs";import ot from"node:path";Ne();$e();function Ys(){let o=new uc("skills").description("Manage skills");return o.addHelpText("after",`
344
346
  Examples:
345
347
  everclaw skills list List all available skills
346
348
  everclaw skills show browser Show details for a skill
@@ -364,20 +366,20 @@ always_on: false
364
366
  TODO: Add skill instructions here.
365
367
  `;rt.writeFileSync(ot.join(s,"SKILL.md"),i),console.log(H.green(`Created skill '${e}' at ${s}/SKILL.md`))}),o.command("install <slug>").description("Install a skill from ClawHub into the workspace").action(async e=>{if(!Rn(e)){console.log(H.red("Invalid skill name. Must start with a lowercase letter or digit and use only lowercase letters, digits, and hyphens.")),process.exitCode=K.GENERAL_ERROR;return}let t=M(),n=X(t.agents.defaults.workspace),{LocalProcessIsolationRunner:r}=await Promise.resolve().then(()=>(pt(),Ho)),s=new r,i="clawhub@latest",a=12e4;console.log(H.cyan(`Installing skill '${e}'...`));try{let l=await s.run({command:{kind:"argv",file:process.platform==="win32"?"npx.cmd":"npx",args:["--yes",i,"install",e,"--workdir",n]},cwd:n,env:{...process.env},timeoutMs:a,maxCaptureBytes:1048576});if(l.status!=="ok"){let u=[l.stdout?.trim(),l.stderr?.trim()].filter(Boolean).join(`
366
368
  `),g=typeof l.exitCode=="number"?` (exit code ${l.exitCode})`:"";console.log(H.red(`Failed to install skill '${e}'${g}: ${u||"unknown error"}`)),process.exitCode=K.GENERAL_ERROR;return}let c=[l.stdout?.trim(),l.stderr?.trim()].filter(Boolean).join(`
367
- `);console.log(H.green(`Skill '${e}' installed successfully.`)),c&&console.log(H.gray(c)),console.log(H.gray("Start a new session so the agent can load the skill."))}catch(l){console.log(H.red(`Failed to install skill '${e}': ${l instanceof Error?l.message:String(l)}`)),process.exitCode=K.CONNECTIVITY_ERROR}}),o}Ne();import ee from"chalk";import{Command as cc}from"commander";function dc(o,e){return o.length>e?o.slice(0,e-3)+"...":o}function Qs(){let o=new cc("mcp").description("Manage MCP server connections");return o.addHelpText("after",`
369
+ `);console.log(H.green(`Skill '${e}' installed successfully.`)),c&&console.log(H.gray(c)),console.log(H.gray("Start a new session so the agent can load the skill."))}catch(l){console.log(H.red(`Failed to install skill '${e}': ${l instanceof Error?l.message:String(l)}`)),process.exitCode=K.CONNECTIVITY_ERROR}}),o}Ne();import ee from"chalk";import{Command as gc}from"commander";function mc(o,e){return o.length>e?o.slice(0,e-3)+"...":o}function Qs(){let o=new gc("mcp").description("Manage MCP server connections");return o.addHelpText("after",`
368
370
  Examples:
369
371
  everclaw mcp list List configured servers
370
372
  everclaw mcp add fs --command npx --args "-y @anthropic/mcp-server-filesystem /path"
371
373
  everclaw mcp test fs Test connectivity
372
374
  everclaw mcp tools fs List tools from a server`),o.command("list").description("List configured MCP servers").action(()=>{let t=M().tools.mcpServers,n=Object.keys(t);if(n.length===0){console.log(ee.gray("No MCP servers configured.")),console.log(ee.gray(`Run ${ee.cyan("everclaw mcp add <name>")} to add one.`));return}console.log(ee.cyan(`
373
375
  MCP Servers
374
- `)),console.log("Name".padEnd(20)+"Transport".padEnd(10)+"Endpoint".padEnd(45)+"Timeout");for(let r of n){let s=t[r],i=s?.url?"http":"stdio",a=s?.url??(s?.command?`${s.command} ${(s.args??[]).join(" ")}`:""),l=s?.toolTimeout?`${s.toolTimeout}s`:"default";console.log(r.padEnd(20)+i.padEnd(10)+dc(a,45).padEnd(45)+l)}console.log("")}),o.command("add <name>").description("Add a new MCP server").option("--command <command>","Command to run (stdio transport)").option("--args <args...>","Arguments for the command").option("--url <url>","HTTP/SSE endpoint URL").option("--timeout <seconds>","Tool timeout in seconds").action((e,t)=>{if(!t.command&&!t.url){console.log(ee.red("Error: Either --command or --url is required.")),process.exitCode=K.GENERAL_ERROR;return}let n;if(t.timeout){let i=parseInt(t.timeout,10);if(!Number.isFinite(i)||i<=0){console.log(ee.red("Error: --timeout must be a positive integer.")),process.exitCode=K.GENERAL_ERROR;return}n=i}let r=M(),s=r.tools.mcpServers;if(s[e]){console.log(ee.yellow(`MCP server '${e}' already exists.`)),process.exitCode=K.GENERAL_ERROR;return}s[e]={command:t.command??"",args:t.args??[],url:t.url??"",toolTimeout:n??60,env:{},headers:{}},oe(r),console.log(ee.green(`Added MCP server '${e}'.`)),console.log(ee.gray("Restart the gateway for changes to take effect."))}),o.command("remove <name>").description("Remove an MCP server from config").action(e=>{let t=M(),n=t.tools.mcpServers;if(!n[e]){console.log(ee.red(`MCP server '${e}' not found.`)),process.exitCode=K.GENERAL_ERROR;return}delete n[e],oe(t),console.log(ee.green(`Removed MCP server '${e}'.`))}),o.command("show <name>").description("Show MCP server details").action(e=>{let r=M().tools.mcpServers[e];if(!r){console.log(ee.red(`MCP server '${e}' not found.`)),process.exitCode=1;return}console.log(ee.cyan(`
376
+ `)),console.log("Name".padEnd(20)+"Transport".padEnd(10)+"Endpoint".padEnd(45)+"Timeout");for(let r of n){let s=t[r],i=s?.url?"http":"stdio",a=s?.url??(s?.command?`${s.command} ${(s.args??[]).join(" ")}`:""),l=s?.toolTimeout?`${s.toolTimeout}s`:"default";console.log(r.padEnd(20)+i.padEnd(10)+mc(a,45).padEnd(45)+l)}console.log("")}),o.command("add <name>").description("Add a new MCP server").option("--command <command>","Command to run (stdio transport)").option("--args <args...>","Arguments for the command").option("--url <url>","HTTP/SSE endpoint URL").option("--timeout <seconds>","Tool timeout in seconds").action((e,t)=>{if(!t.command&&!t.url){console.log(ee.red("Error: Either --command or --url is required.")),process.exitCode=K.GENERAL_ERROR;return}let n;if(t.timeout){let i=parseInt(t.timeout,10);if(!Number.isFinite(i)||i<=0){console.log(ee.red("Error: --timeout must be a positive integer.")),process.exitCode=K.GENERAL_ERROR;return}n=i}let r=M(),s=r.tools.mcpServers;if(s[e]){console.log(ee.yellow(`MCP server '${e}' already exists.`)),process.exitCode=K.GENERAL_ERROR;return}s[e]={command:t.command??"",args:t.args??[],url:t.url??"",toolTimeout:n??60,env:{},headers:{}},oe(r),console.log(ee.green(`Added MCP server '${e}'.`)),console.log(ee.gray("Restart the gateway for changes to take effect."))}),o.command("remove <name>").description("Remove an MCP server from config").action(e=>{let t=M(),n=t.tools.mcpServers;if(!n[e]){console.log(ee.red(`MCP server '${e}' not found.`)),process.exitCode=K.GENERAL_ERROR;return}delete n[e],oe(t),console.log(ee.green(`Removed MCP server '${e}'.`))}),o.command("show <name>").description("Show MCP server details").action(e=>{let r=M().tools.mcpServers[e];if(!r){console.log(ee.red(`MCP server '${e}' not found.`)),process.exitCode=1;return}console.log(ee.cyan(`
375
377
  MCP Server: ${e}
376
378
  `)),console.log(` Transport: ${r.url?"HTTP/SSE":"stdio"}`),r.url?console.log(` URL: ${r.url}`):r.command&&(console.log(` Command: ${r.command}`),r.args?.length&&console.log(` Args: ${r.args.join(" ")}`)),r.toolTimeout&&console.log(` Timeout: ${r.toolTimeout}s`),r.env&&Object.keys(r.env).length>0&&console.log(` Env vars: ${Object.keys(r.env).join(", ")}`),console.log("")}),o.command("test [name]").description("Test connectivity to one or all MCP servers").action(async e=>{let n=M().tools.mcpServers,r=e?[e]:Object.keys(n);if(r.length===0){console.log(ee.gray("No MCP servers configured."));return}if(e&&!n[e]){console.log(ee.red(`MCP server '${e}' not found.`)),process.exitCode=1;return}console.log(ee.cyan(`
377
379
  MCP Connectivity Test
378
380
  `));let{McpClientManager:s}=await Promise.resolve().then(()=>(sn(),gr)),i=new s;i.updateConfig(n);for(let a of r)try{let l=await i.getServerTools(a);console.log(`${a.padEnd(20)} ${ee.green("\u2713 connected")} (${l.length} tools)`)}catch(l){console.log(`${a.padEnd(20)} ${ee.red("\u2717 "+(l instanceof Error?l.message:String(l)))}`),process.exitCode=K.CONNECTIVITY_ERROR}await i.closeAll(),console.log("")}),o.command("tools <name>").description("List tools exposed by an MCP server").action(async e=>{let n=M().tools.mcpServers;if(!n[e]){console.log(ee.red(`MCP server '${e}' not found.`)),process.exitCode=K.GENERAL_ERROR;return}let{McpClientManager:r}=await Promise.resolve().then(()=>(sn(),gr)),s=new r;s.updateConfig(n);try{let i=await s.getServerTools(e);if(i.length===0)console.log(ee.gray(`No tools exposed by '${e}'.`));else{console.log(ee.cyan(`
379
381
  Tools from ${e} (${i.length})
380
- `));for(let a of i)console.log(` ${a.remoteName.padEnd(32)} ${a.description.slice(0,60)}`);console.log("")}}catch(i){console.log(ee.red(`Failed to connect to '${e}': ${i instanceof Error?i.message:String(i)}`)),process.exitCode=K.CONNECTIVITY_ERROR}finally{await s.closeAll()}}),o}le();import be from"node:fs";import St from"node:os";import uc from"node:path";import{execSync as Zs}from"node:child_process";import O from"chalk";import{Command as gc}from"commander";function ho(){return process.platform==="linux"?"linux":process.platform==="darwin"?"macos":"unsupported"}function mc(){let o=process.argv[1];if(o){let e=uc.resolve(o);if(be.existsSync(e))return e}try{let e=Zs("which everclaw 2>/dev/null",{encoding:"utf8"}).trim();if(e&&be.existsSync(e))return e}catch{}return"everclaw"}function pc(o){let e=hn();return`[Unit]
382
+ `));for(let a of i)console.log(` ${a.remoteName.padEnd(32)} ${a.description.slice(0,60)}`);console.log("")}}catch(i){console.log(ee.red(`Failed to connect to '${e}': ${i instanceof Error?i.message:String(i)}`)),process.exitCode=K.CONNECTIVITY_ERROR}finally{await s.closeAll()}}),o}le();import be from"node:fs";import St from"node:os";import pc from"node:path";import{execSync as Zs}from"node:child_process";import O from"chalk";import{Command as fc}from"commander";function ho(){return process.platform==="linux"?"linux":process.platform==="darwin"?"macos":"unsupported"}function hc(){let o=process.argv[1];if(o){let e=pc.resolve(o);if(be.existsSync(e))return e}try{let e=Zs("which everclaw 2>/dev/null",{encoding:"utf8"}).trim();if(e&&be.existsSync(e))return e}catch{}return"everclaw"}function yc(o){let e=hn();return`[Unit]
381
383
  Description=Everclaw AI Assistant Gateway
382
384
  After=network-online.target
383
385
  Wants=network-online.target
@@ -393,7 +395,7 @@ StandardError=append:${e}/gateway.stderr.log
393
395
 
394
396
  [Install]
395
397
  WantedBy=default.target
396
- `}function fc(o){let e=hn();return`<?xml version="1.0" encoding="UTF-8"?>
398
+ `}function bc(o){let e=hn();return`<?xml version="1.0" encoding="UTF-8"?>
397
399
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
398
400
  "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
399
401
  <plist version="1.0">
@@ -416,22 +418,22 @@ WantedBy=default.target
416
418
  <string>${e}/gateway.stderr.log</string>
417
419
  </dict>
418
420
  </plist>
419
- `}function ue(o){try{return{ok:!0,output:Zs(o,{encoding:"utf8",stdio:["pipe","pipe","pipe"]}).trim()}}catch(e){return{ok:!1,output:(e?.stderr||e?.message||String(e)).trim()}}}async function hc(){let o=ho(),e=St.homedir(),t=hn(e),n=mc();be.mkdirSync(t,{recursive:!0}),o==="linux"?await yc(e,n):o==="macos"?await bc(e,n):(console.log(O.red(`Service installation is not supported on '${process.platform}'.`)),console.log(O.gray("Supported: Linux (systemd), macOS (launchd).")),process.exitCode=1)}async function yc(o,e){let t=_r(o),n=yn(o),r=pc(e);console.log(O.cyan("Installing systemd user service...")),console.log(` Binary: ${e}`),console.log(` Unit: ${n}`),be.mkdirSync(t,{recursive:!0}),be.writeFileSync(n,r,"utf8"),console.log(O.green(" Unit file written."));let s=ue("systemctl --user daemon-reload");s.ok||console.log(O.yellow(` Warning: daemon-reload failed: ${s.output}`));let i=ue("systemctl --user enable everclaw");i.ok?console.log(O.green(" Service enabled.")):console.log(O.yellow(` Warning: enable failed: ${i.output}`));let a=ue("systemctl --user start everclaw");a.ok?console.log(O.green(" Service started.")):console.log(O.yellow(` Warning: start failed: ${a.output}`));let l=ue(`loginctl show-user ${St.userInfo().username} -p Linger`);l.ok&&l.output.includes("yes")||(console.log(O.yellow(`
421
+ `}function ue(o){try{return{ok:!0,output:Zs(o,{encoding:"utf8",stdio:["pipe","pipe","pipe"]}).trim()}}catch(e){return{ok:!1,output:(e?.stderr||e?.message||String(e)).trim()}}}async function vc(){let o=ho(),e=St.homedir(),t=hn(e),n=hc();be.mkdirSync(t,{recursive:!0}),o==="linux"?await wc(e,n):o==="macos"?await Sc(e,n):(console.log(O.red(`Service installation is not supported on '${process.platform}'.`)),console.log(O.gray("Supported: Linux (systemd), macOS (launchd).")),process.exitCode=1)}async function wc(o,e){let t=_r(o),n=yn(o),r=yc(e);console.log(O.cyan("Installing systemd user service...")),console.log(` Binary: ${e}`),console.log(` Unit: ${n}`),be.mkdirSync(t,{recursive:!0}),be.writeFileSync(n,r,"utf8"),console.log(O.green(" Unit file written."));let s=ue("systemctl --user daemon-reload");s.ok||console.log(O.yellow(` Warning: daemon-reload failed: ${s.output}`));let i=ue("systemctl --user enable everclaw");i.ok?console.log(O.green(" Service enabled.")):console.log(O.yellow(` Warning: enable failed: ${i.output}`));let a=ue("systemctl --user start everclaw");a.ok?console.log(O.green(" Service started.")):console.log(O.yellow(` Warning: start failed: ${a.output}`));let l=ue(`loginctl show-user ${St.userInfo().username} -p Linger`);l.ok&&l.output.includes("yes")||(console.log(O.yellow(`
420
422
  Note: Linger is not enabled. The service will stop when you log out.`)),console.log(O.gray(` Run: loginctl enable-linger ${St.userInfo().username}`)),console.log(O.gray(" (This may require sudo or admin assistance.)"))),console.log(O.green(`
421
- Service installed successfully.`)),console.log(O.gray("Use: systemctl --user status everclaw")),console.log(O.gray(" systemctl --user stop everclaw")),console.log(O.gray(" journalctl --user -u everclaw -f"))}async function bc(o,e){let t=Or(o),n=bn(o),r=fc(e);console.log(O.cyan("Installing launchd user agent...")),console.log(` Binary: ${e}`),console.log(` Plist: ${n}`),be.mkdirSync(t,{recursive:!0}),be.writeFileSync(n,r,"utf8"),console.log(O.green(" Plist written.")),ue(`launchctl unload ${n} 2>/dev/null`);let s=ue(`launchctl load ${n}`);s.ok?console.log(O.green(" Agent loaded.")):console.log(O.yellow(` Warning: load failed: ${s.output}`)),console.log(O.green(`
422
- Service installed successfully.`)),console.log(O.gray("Use: launchctl list | grep everclaw")),console.log(O.gray(" launchctl unload "+n)),console.log(O.gray(" launchctl load "+n))}async function vc(){let o=ho(),e=St.homedir();o==="linux"?await wc(e):o==="macos"?await Sc(e):(console.log(O.red(`Service uninstall is not supported on '${process.platform}'.`)),process.exitCode=1)}async function wc(o){let e=yn(o);console.log(O.cyan("Uninstalling systemd user service...")),ue("systemctl --user stop everclaw"),ue("systemctl --user disable everclaw"),be.existsSync(e)?(be.unlinkSync(e),console.log(O.green(" Unit file removed."))):console.log(O.gray(" No unit file found.")),ue("systemctl --user daemon-reload"),console.log(O.green(`
423
- Service uninstalled.`))}async function Sc(o){let e=bn(o);console.log(O.cyan("Uninstalling launchd user agent...")),ue(`launchctl unload ${e} 2>/dev/null`).ok&&console.log(O.green(" Agent unloaded.")),be.existsSync(e)?(be.unlinkSync(e),console.log(O.green(" Plist removed."))):console.log(O.gray(" No plist found.")),console.log(O.green(`
424
- Service uninstalled.`))}async function kc(){let o=ho(),e=St.homedir();console.log(O.cyan(`Service Registration Status
425
- `)),o==="linux"?await xc(e):o==="macos"?await Cc(e):console.log(O.gray(`Service management not supported on '${process.platform}'.`))}async function xc(o){let e=yn(o),t=be.existsSync(e);if(console.log("Platform: Linux (systemd user)"),console.log(`Unit file: ${t?O.green(e):O.gray("not found")}`),!t){console.log(O.gray(`
426
- Service is not installed. Run: everclaw service install`));return}let n=ue("systemctl --user is-enabled everclaw 2>/dev/null"),r=ue("systemctl --user is-active everclaw 2>/dev/null");console.log(`Enabled: ${n.ok&&n.output==="enabled"?O.green("yes"):O.yellow(n.output||"unknown")}`),console.log(`Active: ${r.ok&&r.output==="active"?O.green("running"):r.ok?O.yellow(r.output):O.gray("unknown")}`);let s=ue(`loginctl show-user ${St.userInfo().username} -p Linger`),i=s.ok&&s.output.includes("yes");console.log(`Linger: ${i?O.green("enabled"):O.yellow("disabled")} (survives logout)`),i||console.log(O.gray(` Run: loginctl enable-linger ${St.userInfo().username}`))}async function Cc(o){let e=bn(o),t=be.existsSync(e);if(console.log("Platform: macOS (launchd)"),console.log(`Plist: ${t?O.green(e):O.gray("not found")}`),!t){console.log(O.gray(`
427
- Service is not installed. Run: everclaw service install`));return}let n=ue("launchctl list ai.everclaw.gateway 2>/dev/null");if(n.ok){let r=n.output.match(/"PID"\s*=\s*(\d+)/),s=n.output.match(/"LastExitStatus"\s*=\s*(\d+)/);if(r)console.log(`Status: ${O.green("running")} (PID ${r[1]})`);else if(s){let i=parseInt(s[1],10);console.log(`Status: ${i===0?O.green("exited cleanly"):O.yellow(`exited with code ${i}`)}`)}else console.log(`Status: ${O.green("loaded")}`)}else console.log(`Status: ${O.gray("not loaded")}`)}function ei(){let o=new gc("service").description("Manage system service registration (auto-start on reboot)");return o.addHelpText("after",`
423
+ Service installed successfully.`)),console.log(O.gray("Use: systemctl --user status everclaw")),console.log(O.gray(" systemctl --user stop everclaw")),console.log(O.gray(" journalctl --user -u everclaw -f"))}async function Sc(o,e){let t=Or(o),n=bn(o),r=bc(e);console.log(O.cyan("Installing launchd user agent...")),console.log(` Binary: ${e}`),console.log(` Plist: ${n}`),be.mkdirSync(t,{recursive:!0}),be.writeFileSync(n,r,"utf8"),console.log(O.green(" Plist written.")),ue(`launchctl unload ${n} 2>/dev/null`);let s=ue(`launchctl load ${n}`);s.ok?console.log(O.green(" Agent loaded.")):console.log(O.yellow(` Warning: load failed: ${s.output}`)),console.log(O.green(`
424
+ Service installed successfully.`)),console.log(O.gray("Use: launchctl list | grep everclaw")),console.log(O.gray(" launchctl unload "+n)),console.log(O.gray(" launchctl load "+n))}async function kc(){let o=ho(),e=St.homedir();o==="linux"?await xc(e):o==="macos"?await Cc(e):(console.log(O.red(`Service uninstall is not supported on '${process.platform}'.`)),process.exitCode=1)}async function xc(o){let e=yn(o);console.log(O.cyan("Uninstalling systemd user service...")),ue("systemctl --user stop everclaw"),ue("systemctl --user disable everclaw"),be.existsSync(e)?(be.unlinkSync(e),console.log(O.green(" Unit file removed."))):console.log(O.gray(" No unit file found.")),ue("systemctl --user daemon-reload"),console.log(O.green(`
425
+ Service uninstalled.`))}async function Cc(o){let e=bn(o);console.log(O.cyan("Uninstalling launchd user agent...")),ue(`launchctl unload ${e} 2>/dev/null`).ok&&console.log(O.green(" Agent unloaded.")),be.existsSync(e)?(be.unlinkSync(e),console.log(O.green(" Plist removed."))):console.log(O.gray(" No plist found.")),console.log(O.green(`
426
+ Service uninstalled.`))}async function Tc(){let o=ho(),e=St.homedir();console.log(O.cyan(`Service Registration Status
427
+ `)),o==="linux"?await Rc(e):o==="macos"?await Ac(e):console.log(O.gray(`Service management not supported on '${process.platform}'.`))}async function Rc(o){let e=yn(o),t=be.existsSync(e);if(console.log("Platform: Linux (systemd user)"),console.log(`Unit file: ${t?O.green(e):O.gray("not found")}`),!t){console.log(O.gray(`
428
+ Service is not installed. Run: everclaw service install`));return}let n=ue("systemctl --user is-enabled everclaw 2>/dev/null"),r=ue("systemctl --user is-active everclaw 2>/dev/null");console.log(`Enabled: ${n.ok&&n.output==="enabled"?O.green("yes"):O.yellow(n.output||"unknown")}`),console.log(`Active: ${r.ok&&r.output==="active"?O.green("running"):r.ok?O.yellow(r.output):O.gray("unknown")}`);let s=ue(`loginctl show-user ${St.userInfo().username} -p Linger`),i=s.ok&&s.output.includes("yes");console.log(`Linger: ${i?O.green("enabled"):O.yellow("disabled")} (survives logout)`),i||console.log(O.gray(` Run: loginctl enable-linger ${St.userInfo().username}`))}async function Ac(o){let e=bn(o),t=be.existsSync(e);if(console.log("Platform: macOS (launchd)"),console.log(`Plist: ${t?O.green(e):O.gray("not found")}`),!t){console.log(O.gray(`
429
+ Service is not installed. Run: everclaw service install`));return}let n=ue("launchctl list ai.everclaw.gateway 2>/dev/null");if(n.ok){let r=n.output.match(/"PID"\s*=\s*(\d+)/),s=n.output.match(/"LastExitStatus"\s*=\s*(\d+)/);if(r)console.log(`Status: ${O.green("running")} (PID ${r[1]})`);else if(s){let i=parseInt(s[1],10);console.log(`Status: ${i===0?O.green("exited cleanly"):O.yellow(`exited with code ${i}`)}`)}else console.log(`Status: ${O.green("loaded")}`)}else console.log(`Status: ${O.gray("not loaded")}`)}function ei(){let o=new fc("service").description("Manage system service registration (auto-start on reboot)");return o.addHelpText("after",`
428
430
  Examples:
429
431
  everclaw service install Register and start the gateway as a system service
430
432
  everclaw service uninstall Remove the system service
431
433
  everclaw service status Show service registration status
432
434
 
433
- Supported platforms: Linux (systemd user), macOS (launchd LaunchAgent)`),o.command("install").description("Register everclaw gateway as a system service").action(async()=>{await hc()}),o.command("uninstall").description("Remove the everclaw gateway system service").action(async()=>{await vc()}),o.command("status").description("Show service registration status").action(async()=>{await kc()}),o}var Rc=Io(),Ac="0.3.0";function fo(o,e){let t=o?.trim();if(!t)return e;let n=Number(t);if(!Number.isInteger(n)||n<1||n>65535)throw new Error(`Invalid gateway port '${o}'. Expected an integer between 1 and 65535.`);return n}function oi(){if(process.env.DOCKER==="true"||ge.existsSync("/.dockerenv"))return"Docker";if(process.env.INVOCATION_ID)return"systemd";if(process.env.XPC_SERVICE_NAME||process.env.LAUNCH_DAEMON)return"launchd";if(process.env.PM2_HOME||process.env.pm_id)return"pm2";try{if(ge.existsSync("/.dockerenv"))return"Docker"}catch{}return null}function Ec(o){if(process.platform==="win32")return null;try{let{execSync:e}=ci("node:child_process"),n=e(`df -k "${o}"`,{encoding:"utf-8"}).trim().split(`
434
- `);if(n.length<2)return null;let r=n[1].trim().split(/\s+/),s=parseInt(r[3],10);return Number.isNaN(s)?null:s*1024}catch{return null}}async function si(o){let e=!1;try{(await fetch("http://localhost:11434/v1/models",{signal:AbortSignal.timeout(2e3)})).ok&&(e=!0)}catch{}e&&console.log(S.green(" Ollama detected on localhost:11434"));let t=await Fe({type:"select",name:"provider",message:"Choose your provider",choices:[{title:"OpenRouter (recommended \u2014 access 200+ models)",value:"openrouter"},{title:"OpenAI",value:"openai"},{title:"Ollama (local, no API key needed)",value:"ollama"},{title:"Zai (\u667A\u8C31 AI)",value:"zai"},{title:"Custom OpenAI-compatible provider",value:"custom"}]}),n=String(t.provider||"openrouter"),r=Rc[n]??[o.agents.defaults.model],s=await Fe({type:"select",name:"model",message:"Choose your model",choices:r.map(c=>({title:c,value:c}))}),i=String(s.model||r[0]),a="";if(n!=="vllm"&&n!=="ollama"){let c=await Fe({type:"password",name:"apiKey",message:"Enter API key",validate:u=>u&&u.trim().length>0?!0:"API key cannot be empty"});a=String(c.apiKey||"")}let l="";if(n==="custom"||n==="vllm"||n==="ollama"){let c=await Fe({type:"text",name:"apiBase",message:"Enter API base URL",initial:n==="ollama"?"http://localhost:11434/v1":n==="vllm"?"http://localhost:8000/v1":"https://api.openai.com/v1"});l=String(c.apiBase||"").trim()}if(n==="custom"){let c;try{c=new URL(l).hostname.replace(/\./g,"-")}catch{c="custom-provider"}o.customLlmProviders.push({name:c,baseUrl:l,apiKey:a,apiFormat:"v1/chat/completions",models:[{id:i,displayName:i}],extraHeaders:null}),o.agents.defaults.provider=Wt(c),o.agents.defaults.model=i}else{if(o.agents.defaults.provider=n,o.agents.defaults.model=i,n in o.providers){let c=o.providers[n];c&&(c.apiKey=a)}if((n==="vllm"||n==="ollama")&&l&&n in o.providers){let c=o.providers[n];c&&(c.apiBase=l)}}}async function ii(o){if((await Fe({type:"confirm",name:"wantChannel",message:"Do you want to configure a chat channel now?",initial:!0})).wantChannel){let t=await Fe({type:"select",name:"channel",message:"Choose chat channel",choices:[{title:"Telegram",value:"telegram"},{title:"Discord",value:"discord"}]}),n=String(t.channel||"telegram");if(n==="telegram"){let r=await Fe({type:"password",name:"token",message:"Enter Telegram Bot Token",validate:s=>s&&s.trim().length>0?!0:"Token cannot be empty"});o.channels.telegram.enabled=!0,o.channels.telegram.token=String(r.token||"").trim()}else if(n==="discord"){let r=await Fe({type:"password",name:"token",message:"Enter Discord Bot Token",validate:s=>s&&s.trim().length>0?!0:"Token cannot be empty"});o.channels.discord.enabled=!0,o.channels.discord.token=String(r.token||"").trim()}}}function ai(o){let e=new Tc;if(e.name("everclaw").description("everclaw - Personal AI Assistant").version(Ac,"-v, --version","show version").option("--json","Output in JSON format for scripting").addHelpText("after",`
435
+ Supported platforms: Linux (systemd user), macOS (launchd LaunchAgent)`),o.command("install").description("Register everclaw gateway as a system service").action(async()=>{await vc()}),o.command("uninstall").description("Remove the everclaw gateway system service").action(async()=>{await kc()}),o.command("status").description("Show service registration status").action(async()=>{await Tc()}),o}var Pc=Io(),Ic="0.3.0";function fo(o,e){let t=o?.trim();if(!t)return e;let n=Number(t);if(!Number.isInteger(n)||n<1||n>65535)throw new Error(`Invalid gateway port '${o}'. Expected an integer between 1 and 65535.`);return n}function oi(){if(process.env.DOCKER==="true"||ge.existsSync("/.dockerenv"))return"Docker";if(process.env.INVOCATION_ID)return"systemd";if(process.env.XPC_SERVICE_NAME||process.env.LAUNCH_DAEMON)return"launchd";if(process.env.PM2_HOME||process.env.pm_id)return"pm2";try{if(ge.existsSync("/.dockerenv"))return"Docker"}catch{}return null}function Mc(o){if(process.platform==="win32")return null;try{let{execSync:e}=ci("node:child_process"),n=e(`df -k "${o}"`,{encoding:"utf-8"}).trim().split(`
436
+ `);if(n.length<2)return null;let r=n[1].trim().split(/\s+/),s=parseInt(r[3],10);return Number.isNaN(s)?null:s*1024}catch{return null}}async function si(o){let e=!1;try{(await fetch("http://localhost:11434/v1/models",{signal:AbortSignal.timeout(2e3)})).ok&&(e=!0)}catch{}e&&console.log(S.green(" Ollama detected on localhost:11434"));let t=await Fe({type:"select",name:"provider",message:"Choose your provider",choices:[{title:"OpenRouter (recommended \u2014 access 200+ models)",value:"openrouter"},{title:"OpenAI",value:"openai"},{title:"Ollama (local, no API key needed)",value:"ollama"},{title:"Zai (\u667A\u8C31 AI)",value:"zai"},{title:"Custom OpenAI-compatible provider",value:"custom"}]}),n=String(t.provider||"openrouter"),r=Pc[n]??[o.agents.defaults.model],s=await Fe({type:"select",name:"model",message:"Choose your model",choices:r.map(c=>({title:c,value:c}))}),i=String(s.model||r[0]),a="";if(n!=="vllm"&&n!=="ollama"){let c=await Fe({type:"password",name:"apiKey",message:"Enter API key",validate:u=>u&&u.trim().length>0?!0:"API key cannot be empty"});a=String(c.apiKey||"")}let l="";if(n==="custom"||n==="vllm"||n==="ollama"){let c=await Fe({type:"text",name:"apiBase",message:"Enter API base URL",initial:n==="ollama"?"http://localhost:11434/v1":n==="vllm"?"http://localhost:8000/v1":"https://api.openai.com/v1"});l=String(c.apiBase||"").trim()}if(n==="custom"){let c;try{c=new URL(l).hostname.replace(/\./g,"-")}catch{c="custom-provider"}o.customLlmProviders.push({name:c,baseUrl:l,apiKey:a,apiFormat:"v1/chat/completions",models:[{id:i,displayName:i}],extraHeaders:null}),o.agents.defaults.provider=Wt(c),o.agents.defaults.model=i}else{if(o.agents.defaults.provider=n,o.agents.defaults.model=i,n in o.providers){let c=o.providers[n];c&&(c.apiKey=a)}if((n==="vllm"||n==="ollama")&&l&&n in o.providers){let c=o.providers[n];c&&(c.apiBase=l)}}}async function ii(o){if((await Fe({type:"confirm",name:"wantChannel",message:"Do you want to configure a chat channel now?",initial:!0})).wantChannel){let t=await Fe({type:"select",name:"channel",message:"Choose chat channel",choices:[{title:"Telegram",value:"telegram"},{title:"Discord",value:"discord"}]}),n=String(t.channel||"telegram");if(n==="telegram"){let r=await Fe({type:"password",name:"token",message:"Enter Telegram Bot Token",validate:s=>s&&s.trim().length>0?!0:"Token cannot be empty"});o.channels.telegram.enabled=!0,o.channels.telegram.token=String(r.token||"").trim()}else if(n==="discord"){let r=await Fe({type:"password",name:"token",message:"Enter Discord Bot Token",validate:s=>s&&s.trim().length>0?!0:"Token cannot be empty"});o.channels.discord.enabled=!0,o.channels.discord.token=String(r.token||"").trim()}}}function ai(o){let e=new Ec;if(e.name("everclaw").description("everclaw - Personal AI Assistant").version(Ic,"-v, --version","show version").option("--json","Output in JSON format for scripting").addHelpText("after",`
435
437
  Examples:
436
438
  everclaw onboard Interactive setup wizard
437
439
  everclaw gateway Start the gateway server
@@ -468,12 +470,12 @@ Examples:
468
470
  Channels:`);for(let[N,z]of Object.entries($)){let ae=z?.running?S.green("connected"):S.gray("disconnected");console.log(` ${N.padEnd(12)} ${ae}`)}}}else console.log(`Gateway: ${S.gray("not running")}`);console.log(`
469
471
  Model: ${c.agents.defaults.model}`),console.log(`Provider: ${Xe(c)??"none"}`),console.log(`Config: ${l} ${ge.existsSync(l)?"yes":"no"}`),console.log(`Workspace: ${u} ${ge.existsSync(u)?"yes":"no"}`),console.log(`
470
472
  RTK Token Compression:`),v.installed&&v.version?(console.log(` Status: ${S.green("Available")} (v${v.version})`),console.log(` Binary: ${v.binaryPath}`)):v.installed?(console.log(` Status: ${S.yellow("Installed but broken")}`),console.log(` Binary: ${v.binaryPath}`),console.log(S.gray(` Run ${S.cyan("everclaw rtk install --force")} to reinstall`))):(console.log(` Status: ${S.gray("Not installed")}`),c.tools.rtk.autoInstall?console.log(S.gray(" Auto-install is enabled and will download on first gateway start")):console.log(S.gray(` Run ${S.cyan("everclaw rtk install")} to install`)))}),e.command("doctor").description("Validate provider/model configuration and connectivity").action(async()=>{let a=!!e.opts().json,l=M(),c=Kt(l,process.env),u=Xe(c),g=[],h={ok:!0,warnings:[]},T=Ee(),v=T&&Ae(T.pid);h.system={gateway:v?{running:!0,pid:T.pid,port:T.port,uptime:dt(T.startedAt)}:{running:!1},nodeVersion:process.versions.node,root:process.getuid?.()===0,supervisor:oi()??"standalone"},a||(console.log(S.cyan(`everclaw doctor
471
- `)),console.log(S.bold("System:")),console.log(v?` Gateway: ${S.green("running")} (PID ${T.pid}, port ${T.port}, uptime ${dt(T.startedAt)})`:` Gateway: ${S.gray("not running")}`));let d=process.versions.node,b=parseInt(d.split(".")[0]??"0",10);b<20&&g.push("Node.js version below 20 may have compatibility issues");let $=process.getuid?.()===0;if($&&g.push("Running as root is not recommended for security"),!a){b>=20?console.log(` Node.js: ${S.green(d)}`):console.log(` Node.js: ${S.yellow(d)} (recommend v20+)`),console.log($?` Running as: ${S.red("root")} (not recommended)`:` Running as: ${S.green("non-root")}`);let A=oi();console.log(A?` Supervisor: ${S.green(A)}`:` Supervisor: ${S.gray("standalone")}`)}let k=Rt();if(ge.existsSync(k))try{let j=!!(ge.statSync(k).mode&511&7);h.system.configPermissions={ok:!j,path:k},j&&g.push("Config file is world-readable \u2014 contains API keys"),a||console.log(j?` Config: ${S.yellow("world-readable")} (${k})`:` Config: ${S.green("ok")} (${k})`)}catch{a||console.log(` Config: ${S.gray("unable to check")}`)}try{let A=De();ge.statSync(A);let I=Ec(A);if(I!==null){let j=Math.round(I/1048576);h.system.diskSpace={freeMB:j,path:A,ok:I>=100*1024*1024},I<100*1024*1024&&g.push(`Low disk space: ${j}MB free in ${A}`),a||(I<100*1024*1024?console.log(` Disk space: ${S.yellow(`${j}MB free`)} (${A})`):console.log(` Disk space: ${S.green(`${j}MB free`)} (${A})`))}}catch{}let U=X(c.agents.defaults.workspace);if(ge.existsSync(U))try{let j=!!(ge.statSync(U).mode&511&2);h.system.workspace={ok:!j,path:U},j&&g.push("Workspace directory is world-writable \u2014 may allow unauthorized file modifications"),a||console.log(j?` Workspace: ${S.yellow("world-writable")} (${U})`:` Workspace: ${S.green("ok")} (${U})`)}catch{a||console.log(` Workspace: ${S.gray("unable to check")}`)}else h.system.workspace={ok:!0,path:U,created:!1},a||console.log(` Workspace: ${S.gray("not created")} (${U})`);let L=c.security;if(h.security={enabled:L.enabled,auth:L.auth.enabled,toolGuard:L.toolGuard.enabled,skillScanner:L.skillScanner.enabled,inputSanitizer:L.inputSanitizer.enabled,pathBoundary:c.tools.restrictToWorkspace},a)L.toolGuard.enabled&&L.toolGuard.failOpen&&g.push("Tool guard is fail-open \u2014 consider fail-closed for production"),L.skillScanner.enabled||g.push("Skill scanner disabled \u2014 unsafe skills will not be blocked"),c.tools.restrictToWorkspace||g.push("Path boundary not restricted \u2014 agent can access files outside workspace"),!L.auth.enabled&&c.gateway.host!=="127.0.0.1"&&c.gateway.host!=="localhost"&&g.push("Dashboard exposed on non-loopback without auth");else{if(console.log(S.bold(`
473
+ `)),console.log(S.bold("System:")),console.log(v?` Gateway: ${S.green("running")} (PID ${T.pid}, port ${T.port}, uptime ${dt(T.startedAt)})`:` Gateway: ${S.gray("not running")}`));let d=process.versions.node,b=parseInt(d.split(".")[0]??"0",10);b<20&&g.push("Node.js version below 20 may have compatibility issues");let $=process.getuid?.()===0;if($&&g.push("Running as root is not recommended for security"),!a){b>=20?console.log(` Node.js: ${S.green(d)}`):console.log(` Node.js: ${S.yellow(d)} (recommend v20+)`),console.log($?` Running as: ${S.red("root")} (not recommended)`:` Running as: ${S.green("non-root")}`);let A=oi();console.log(A?` Supervisor: ${S.green(A)}`:` Supervisor: ${S.gray("standalone")}`)}let k=Rt();if(ge.existsSync(k))try{let F=!!(ge.statSync(k).mode&511&7);h.system.configPermissions={ok:!F,path:k},F&&g.push("Config file is world-readable \u2014 contains API keys"),a||console.log(F?` Config: ${S.yellow("world-readable")} (${k})`:` Config: ${S.green("ok")} (${k})`)}catch{a||console.log(` Config: ${S.gray("unable to check")}`)}try{let A=De();ge.statSync(A);let I=Mc(A);if(I!==null){let F=Math.round(I/1048576);h.system.diskSpace={freeMB:F,path:A,ok:I>=100*1024*1024},I<100*1024*1024&&g.push(`Low disk space: ${F}MB free in ${A}`),a||(I<100*1024*1024?console.log(` Disk space: ${S.yellow(`${F}MB free`)} (${A})`):console.log(` Disk space: ${S.green(`${F}MB free`)} (${A})`))}}catch{}let U=X(c.agents.defaults.workspace);if(ge.existsSync(U))try{let F=!!(ge.statSync(U).mode&511&2);h.system.workspace={ok:!F,path:U},F&&g.push("Workspace directory is world-writable \u2014 may allow unauthorized file modifications"),a||console.log(F?` Workspace: ${S.yellow("world-writable")} (${U})`:` Workspace: ${S.green("ok")} (${U})`)}catch{a||console.log(` Workspace: ${S.gray("unable to check")}`)}else h.system.workspace={ok:!0,path:U,created:!1},a||console.log(` Workspace: ${S.gray("not created")} (${U})`);let L=c.security;if(h.security={enabled:L.enabled,auth:L.auth.enabled,toolGuard:L.toolGuard.enabled,skillScanner:L.skillScanner.enabled,inputSanitizer:L.inputSanitizer.enabled,pathBoundary:c.tools.restrictToWorkspace},a)L.toolGuard.enabled&&L.toolGuard.failOpen&&g.push("Tool guard is fail-open \u2014 consider fail-closed for production"),L.skillScanner.enabled||g.push("Skill scanner disabled \u2014 unsafe skills will not be blocked"),c.tools.restrictToWorkspace||g.push("Path boundary not restricted \u2014 agent can access files outside workspace"),!L.auth.enabled&&c.gateway.host!=="127.0.0.1"&&c.gateway.host!=="localhost"&&g.push("Dashboard exposed on non-loopback without auth");else{if(console.log(S.bold(`
472
474
  Security:`)),console.log(` Master switch: ${L.enabled?S.green("enabled"):S.gray("disabled")}`),L.auth.enabled){let A=L.auth.sessionTtlS?`${Math.floor(L.auth.sessionTtlS/60)}min`:"default",I=L.auth.idleTimeoutS?`${Math.floor(L.auth.idleTimeoutS/60)}min`:"off";console.log(` Authentication: ${S.green("enabled")} (PIN, session TTL: ${A}, idle lock: ${I})`)}else console.log(` Authentication: ${S.gray("disabled")}`),c.gateway.host!=="127.0.0.1"&&c.gateway.host!=="localhost"&&g.push("Dashboard exposed on non-loopback without auth");console.log(` Tool Guard: ${L.toolGuard.enabled?S.green("enabled"):S.gray("disabled")}`),L.toolGuard.enabled&&L.toolGuard.failOpen&&g.push("Tool guard is fail-open \u2014 consider fail-closed for production"),console.log(` Skill Scanner: ${L.skillScanner.enabled?S.green("enabled"):S.gray("disabled")}`),L.skillScanner.enabled||g.push("Skill scanner disabled \u2014 unsafe skills will not be blocked"),console.log(` Input Sanitizer: ${L.inputSanitizer.enabled?S.green("enabled"):S.gray("disabled")}`),console.log(` Path Boundary: ${c.tools.restrictToWorkspace?S.green("workspace-restricted"):S.yellow("unrestricted")}`),c.tools.restrictToWorkspace||g.push("Path boundary not restricted \u2014 agent can access files outside workspace")}let N=$o(c);for(let A of N)g.includes(A)||g.push(A);h.provider={name:u??null,model:c.agents.defaults.model},a||(console.log(S.bold(`
473
- Provider:`)),console.log(` Resolved: ${u??"none"}`),console.log(` Model: ${c.agents.defaults.model}`));let F=await new Te().getStatus();h.rtk={installed:F.installed,version:F.version??null,binaryPath:F.binaryPath},F.installed&&F.version&&!wt(F.version,Ce)&&g.push(`RTK version ${F.version} is below minimum ${Ce}`),a||(console.log(S.bold(`
474
- RTK Token Compression:`)),F.installed&&F.version?wt(F.version,Ce)?console.log(` Status: ${S.green("Available")} (v${F.version})`):console.log(` Status: ${S.yellow("Outdated")} (v${F.version}, min: ${Ce})`):console.log(` Status: ${S.gray("Not installed")}`));let ae=Object.keys(c.tools.mcpServers);if(ae.length>0){let A={};a||console.log(S.bold(`
475
- MCP Servers:`));for(let I of ae)try{let{McpClientManager:j}=await Promise.resolve().then(()=>(sn(),gr)),q=new j;q.updateConfig(c.tools.mcpServers);let re=await q.getServerTools(I);await q.closeAll(),A[I]={connected:!0,tools:re.length},a||console.log(` ${I.padEnd(20)} ${S.green("\u2713 connected")} (${re.length} tools)`)}catch(j){let q=j instanceof Error?j.message:String(j);A[I]={connected:!1,error:q},a||console.log(` ${I.padEnd(20)} ${S.red("\u2717 "+q)}`)}h.mcp=A}let J={};if(c.channels.telegram.enabled){let A=c.channels.telegram.token,I=A?/^\d+:[A-Za-z0-9_-]{30,}$/.test(A):!1;J.telegram={enabled:!0,configured:!!A,validFormat:I},A?I||g.push("Telegram token format does not match expected pattern"):g.push("Telegram channel enabled but no token configured")}if(c.channels.discord.enabled){let A=c.channels.discord.token,I=A?A.length>=50&&/^[A-Za-z0-9._-]+$/.test(A):!1;J.discord={enabled:!0,configured:!!A,validFormat:I},A?I||g.push("Discord token format does not match expected pattern"):g.push("Discord channel enabled but no token configured")}if(Object.keys(J).length>0&&(h.channels=J,!a)){if(console.log(S.bold(`
475
+ Provider:`)),console.log(` Resolved: ${u??"none"}`),console.log(` Model: ${c.agents.defaults.model}`));let B=await new Te().getStatus();h.rtk={installed:B.installed,version:B.version??null,binaryPath:B.binaryPath},B.installed&&B.version&&!wt(B.version,Ce)&&g.push(`RTK version ${B.version} is below minimum ${Ce}`),a||(console.log(S.bold(`
476
+ RTK Token Compression:`)),B.installed&&B.version?wt(B.version,Ce)?console.log(` Status: ${S.green("Available")} (v${B.version})`):console.log(` Status: ${S.yellow("Outdated")} (v${B.version}, min: ${Ce})`):console.log(` Status: ${S.gray("Not installed")}`));let ae=Object.keys(c.tools.mcpServers);if(ae.length>0){let A={};a||console.log(S.bold(`
477
+ MCP Servers:`));for(let I of ae)try{let{McpClientManager:F}=await Promise.resolve().then(()=>(sn(),gr)),q=new F;q.updateConfig(c.tools.mcpServers);let re=await q.getServerTools(I);await q.closeAll(),A[I]={connected:!0,tools:re.length},a||console.log(` ${I.padEnd(20)} ${S.green("\u2713 connected")} (${re.length} tools)`)}catch(F){let q=F instanceof Error?F.message:String(F);A[I]={connected:!1,error:q},a||console.log(` ${I.padEnd(20)} ${S.red("\u2717 "+q)}`)}h.mcp=A}let J={};if(c.channels.telegram.enabled){let A=c.channels.telegram.token,I=A?/^\d+:[A-Za-z0-9_-]{30,}$/.test(A):!1;J.telegram={enabled:!0,configured:!!A,validFormat:I},A?I||g.push("Telegram token format does not match expected pattern"):g.push("Telegram channel enabled but no token configured")}if(c.channels.discord.enabled){let A=c.channels.discord.token,I=A?A.length>=50&&/^[A-Za-z0-9._-]+$/.test(A):!1;J.discord={enabled:!0,configured:!!A,validFormat:I},A?I||g.push("Discord token format does not match expected pattern"):g.push("Discord channel enabled but no token configured")}if(Object.keys(J).length>0&&(h.channels=J,!a)){if(console.log(S.bold(`
476
478
  Channel Tokens:`)),c.channels.telegram.enabled){let A=c.channels.telegram.token;A&&/^\d+:[A-Za-z0-9_-]{30,}$/.test(A)?console.log(` Telegram: ${S.green("valid format")}`):console.log(A?` Telegram: ${S.yellow("unusual format")} \u2014 verify the token is correct`:` Telegram: ${S.red("not configured")}`)}if(c.channels.discord.enabled){let A=c.channels.discord.token;A&&A.length>=50&&/^[A-Za-z0-9._-]+$/.test(A)?console.log(` Discord: ${S.green("valid format")}`):console.log(A?` Discord: ${S.yellow("unusual format")} \u2014 verify the token is correct`:` Discord: ${S.red("not configured")}`)}}a||console.log(S.bold(`
477
479
  LLM Connectivity:`));let Z;try{Z=_e(c)}catch(A){h.llm={connected:!1,error:String(A)},h.ok=!1,h.warnings=g,console.log(a?JSON.stringify(h,null,2):` ${S.red("Failed to create provider: "+String(A))}`),process.exitCode=K.GENERAL_ERROR;return}try{let A=await Z.chat({messages:[{role:"user",content:"Reply with: OK"}],model:c.agents.defaults.model,maxTokens:16,temperature:0});if((A.content||"").toLowerCase().includes("error")){h.llm={connected:!1,error:A.content},h.ok=!1,h.warnings=g,console.log(a?JSON.stringify(h,null,2):` ${S.red("Failed: "+A.content)}`),process.exitCode=K.CONNECTIVITY_ERROR;return}h.llm={connected:!0},a||console.log(` ${S.green("Passed")}: ${A.content??"(empty response)"}`)}catch(A){h.llm={connected:!1,error:String(A)},h.ok=!1,h.warnings=g,console.log(a?JSON.stringify(h,null,2):` ${S.red("Failed: "+String(A))}`),process.exitCode=K.CONNECTIVITY_ERROR;return}if(h.warnings=g,a){console.log(JSON.stringify(h,null,2));return}if(g.length>0){console.log(S.bold(`
478
480
  Warnings:`));for(let A of g)console.log(` ${S.yellow("\u26A0")} ${A}`)}console.log(S.green(`
479
- Doctor check complete.`))}),e.command("provider").description("Manage providers").command("login").argument("<provider>").action(i=>{let a=i.replace(/-/g,"_");if(!["openai_codex","github_copilot"].includes(a)){console.log(`Unknown OAuth provider: ${i}. Supported: openai-codex, github-copilot`),process.exitCode=1;return}console.log(`OAuth login for ${i} is not yet implemented in TypeScript port.`)}),e}Eo(process.argv);var Pc=ai();Pc.parseAsync(process.argv);
481
+ Doctor check complete.`))}),e.command("provider").description("Manage providers").command("login").argument("<provider>").action(i=>{let a=i.replace(/-/g,"_");if(!["openai_codex","github_copilot"].includes(a)){console.log(`Unknown OAuth provider: ${i}. Supported: openai-codex, github-copilot`),process.exitCode=1;return}console.log(`OAuth login for ${i} is not yet implemented in TypeScript port.`)}),e}Eo(process.argv);var _c=ai();_c.parseAsync(process.argv);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "everclaw",
3
- "version": "0.3.4",
3
+ "version": "0.3.6",
4
4
  "description": "Lightweight AI coding agent runtime for servers and CLI",
5
5
  "keywords": [
6
6
  "coding-agent",