grix-connector 3.7.0 → 3.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- import{EventEmitter as S}from"events";import{log as l}from"../core/log/index.js";import{AgentEventType as c}from"../types/events.js";import{mapSessionUpdate as M}from"./event-mapper.js";class h extends Error{authMethods;constructor(e){super("ACP authentication required"),this.name="AcpAuthRequiredError",this.authMethods=e}}function p(a){if(!a||typeof a!="object")return!1;const e=a;return e.code===-32e3?!0:e.code===-32603&&e.data?.details?/\b(401|token\s*expired|access\s*token)\b/i.test(e.data.details):!1}function m(a){return!a||typeof a!="object"?[{id:"oauth"}]:a.data?.authMethods??[{id:"oauth"}]}class u extends S{acpSessionId="";alive=!1;pendingPermissions=new Map;availableModes=[];availableModels=[];currentMode="";currentModel="";listSupported=!1;loadSupported=!1;_supportsCommandsExecute=!1;_availableCommands=[];transport;settleTimer=null;static SETTLE_MS=3e3;pendingToolCallIds=new Set;settleSuppressedSince=0;static SETTLE_SUPPRESS_MAX_MS=900*1e3;constructor(){super(),this.transport=null}get sessionId(){return this.acpSessionId}get isAlive(){return this.alive}get modes(){return[...this.availableModes]}get mode(){return this.currentMode}get models(){return[...this.availableModels]}get model(){return this.currentModel}get sessionOptions(){return{modes:[...this.availableModes],currentModeId:this.currentMode,models:[...this.availableModels],currentModelId:this.currentModel}}get supportsCommandsExecute(){return this._supportsCommandsExecute}get availableCommands(){return[...this._availableCommands]}async connect(e){this.transport=e.transport,this.transport.on("close",()=>{this.alive&&(this.alive=!1,this.emit("session-lost"))}),this.transport.setHandlers((n,r)=>{n==="session/update"?this.handleSessionUpdate(r):n==="_kiro.dev/metadata"?this.handleKiroMetadata(r):n==="_kiro.dev/commands/available"?this.handleCommandsAvailable(r):n==="_kiro.dev/compaction/status"?this.emit("compactionStatus",r):n==="_kiro.dev/clear/status"&&this.emit("clearStatus",r)},(n,r,d)=>{n==="session/request_permission"?this.handlePermissionRequest(r,d):n.startsWith("cursor/")?this.transport.respondSuccess(r,{}).catch(()=>{}):this.transport.respondError(r,-32601,"method not implemented").catch(()=>{})});const t=await this.initialize();this.listSupported=!!t.agentCapabilities?.sessionCapabilities?.list,this.loadSupported=!!t.agentCapabilities?.loadSession;const i=t.agentCapabilities??{};if(this._supportsCommandsExecute=!!(i.extensions?.["_kiro.dev/commands"]||i.commands),e.authMethod)try{await this.transport.call("authenticate",{methodId:e.authMethod})}catch(n){throw p(n)?new h(m(n)):n}const s=e.sessionId&&e.sessionId!=="__continue__";let o=!1;if(s){if(!this.loadSupported)throw new Error(`session/load not supported by agent, cannot resume session ${e.sessionId}`);try{await this.loadSession(e.sessionId,e)&&(o=!0)}catch(n){throw p(n)?new h(m(n)):n}if(!o)throw new Error(`session/load failed for session ${e.sessionId}`)}else try{await this.newSession(e)}catch(n){throw p(n)?new h(m(n)):n}e.initialMode&&await this.setLiveMode(e.initialMode).catch(()=>{}),e.initialModel&&await this.setModel(e.initialModel).catch(()=>{}),this.alive=!0}async initialize(){return await this.transport.call("initialize",{protocolVersion:1,clientCapabilities:{fs:{readTextFile:!1,writeTextFile:!1},terminal:!1},clientInfo:{name:"grix-connector-acp",version:"0.2.0"}})}buildMcpEntries(e){return(e??[]).map(t=>{const i={name:t.name,command:t.command};return t.args&&(i.args=t.args),t.env&&Object.keys(t.env).length>0&&(i.env=Object.entries(t.env).map(([s,o])=>({name:s,value:o}))),i})}async newSession(e){const t=this.buildMcpEntries(e.mcpServers),i={cwd:e.cwd||process.cwd(),mcpServers:t};e.additionalDirectories&&e.additionalDirectories.length>0&&(i.additionalDirectories=e.additionalDirectories);const s=await this.transport.call("session/new",i);if(!s?.sessionId)throw new Error("session/new returned empty sessionId");this.acpSessionId=s.sessionId,this.absorbModes(s.modes),this.absorbModels(s.models)}async loadSession(e,t){const i=this.buildMcpEntries(t.mcpServers),s={sessionId:e,cwd:t.cwd||process.cwd(),mcpServers:i};t.additionalDirectories&&t.additionalDirectories.length>0&&(s.additionalDirectories=t.additionalDirectories);const o=await this.transport.call("session/load",s);return o?.sessionId?(this.acpSessionId=o.sessionId,this.absorbModes(o.modes),this.absorbModels(o.models),!0):o&&(o.modes||o.models)?(this.acpSessionId=e,this.absorbModes(o.modes),this.absorbModels(o.models),!0):!1}absorbModes(e){e?.availableModes?.length&&(this.availableModes=[...e.availableModes],e.currentModeId&&(this.currentMode=e.currentModeId))}absorbModels(e){e?.availableModels?.length&&(this.availableModels=[...e.availableModels],e.currentModelId&&(this.currentModel=e.currentModelId))}async send(e,t,i){if(!this.alive)throw new Error("session not active");if(!this.acpSessionId)throw new Error("no agent session id");const s=[{type:"text",text:e}];if(t)for(const o of t)s.push({type:"image",data:o.data.toString("base64"),mimeType:o.mimeType});this.pendingToolCallIds.clear(),this.settleSuppressedSince=0,await this.transport.call("session/prompt",{sessionId:this.acpSessionId,prompt:s,...this.currentModel?{modelId:this.currentModel}:{}}),this.scheduleSettledResult()}scheduleSettledResult(){this.settleTimer&&clearTimeout(this.settleTimer),this.settleTimer=setTimeout(()=>{if(this.settleTimer=null,!!this.alive){if(this.pendingToolCallIds.size>0){if(this.settleSuppressedSince===0&&(this.settleSuppressedSince=Date.now()),Date.now()-this.settleSuppressedSince<u.SETTLE_SUPPRESS_MAX_MS){l.info("acp-client",`settle suppressed: ${this.pendingToolCallIds.size} pending tool call(s) for session ${this.acpSessionId}`),this.scheduleSettledResult();return}l.warn("acp-client",`settle suppression exceeded ${u.SETTLE_SUPPRESS_MAX_MS/6e4}min with ${this.pendingToolCallIds.size} pending tool call(s), emitting Result anyway`)}this.settleSuppressedSince=0,l.info("acp-client",`settle timer fired, emitting Result for session ${this.acpSessionId}`),this.emit("event",{type:c.Result,sessionId:this.acpSessionId,done:!0})}},u.SETTLE_MS),this.settleTimer.unref()}clearSettleTimer(){this.settleTimer&&(clearTimeout(this.settleTimer),this.settleTimer=null),this.settleSuppressedSince=0}async cancel(){if(this.acpSessionId){this.pendingToolCallIds.clear(),this.settleSuppressedSince=0;try{await this.transport.notify("session/cancel",{sessionId:this.acpSessionId})}catch{}}}async authenticate(e){await this.transport.call("authenticate",{methodId:e})}async respondPermission(e,t){const i=this.pendingPermissions.get(e);if(!i)throw new Error(`unknown permission request: ${e}`);this.pendingPermissions.delete(e);const s=this.pickPermissionOptionId(t.behavior,i.options),o=this.buildPermissionResult(t.behavior,s);await this.transport.respondSuccess(i.rpcId,o)}async ping(e=1e4){if(!this.alive)return!1;try{const t=new AbortController,i=setTimeout(()=>t.abort(),e);return await this.transport.call("session/list",{},t.signal),clearTimeout(i),!0}catch(t){return t?.code===-32601}}async setLiveMode(e){if(!this.acpSessionId)return l.warn("acp-client",`setLiveMode("${e}") skipped: no active session`),!1;const t=this.matchAvailableMode(e);if(!t)return l.warn("acp-client",`setLiveMode("${e}") failed: mode not found in available [${this.availableModes.map(i=>i.id).join(",")}]`),!1;try{const i=new AbortController,s=setTimeout(()=>i.abort(),8e3);return await this.transport.call("session/set_mode",{sessionId:this.acpSessionId,modeId:t},i.signal),clearTimeout(s),this.currentMode=t,!0}catch(i){return l.warn("acp-client",`setLiveMode("${t}") RPC failed: ${i instanceof Error?i.message:i}`),!1}}async setModel(e){if(!this.acpSessionId)return l.warn("acp-client",`setModel("${e}") skipped: no active session`),!1;try{const t=new AbortController,i=setTimeout(()=>t.abort(),8e3);return await this.transport.call("session/set_model",{sessionId:this.acpSessionId,modelId:e},t.signal),clearTimeout(i),this.currentModel=e,!0}catch(t){return l.warn("acp-client",`setModel("${e}") RPC failed: ${t instanceof Error?t.message:t}`),!1}}handleSessionUpdate(e){this.emit("activity");const t=e?.update?.sessionUpdate,i=t==="usage_update";if(t==="tool_call"||t==="tool_call_update"){const o=e?.update??{},n=String(o.toolCallId??""),r=String(o.status??"").toLowerCase().trim();n&&(r==="completed"||r==="failed"?this.pendingToolCallIds.delete(n):t==="tool_call"&&this.pendingToolCallIds.add(n))}this.settleTimer&&!i&&this.scheduleSettledResult();const s=M(this.acpSessionId,e);for(const o of s)o.sessionId||(o.sessionId=this.acpSessionId),o.type===c.Result&&(this.pendingToolCallIds.clear(),this.settleTimer&&this.clearSettleTimer()),this.emit("event",o)}handleKiroMetadata(e){const i=e?.contextUsagePercentage;typeof i!="number"||!Number.isFinite(i)||this.emit("event",{type:c.ContextWindowUpdate,sessionId:this.acpSessionId,contextWindow:{usedPercentage:Math.min(100,Math.max(0,i))}})}handleCommandsAvailable(e){const t=e,i=Array.isArray(t?.commands)?t.commands:[];this._availableCommands=i.map(s=>({name:String(s.name??""),description:s.description?String(s.description):void 0,args:s.args?String(s.args):void 0})),this._supportsCommandsExecute=!0,this.emit("commandsAvailable",this._availableCommands)}async executeCommand(e,t){if(!this.alive)throw new Error("session not active");if(!this.acpSessionId)throw new Error("no agent session id");const i=new AbortController,s=setTimeout(()=>i.abort(),2e4);try{const o=await this.transport.call("_kiro.dev/commands/execute",{sessionId:this.acpSessionId,command:e,...t?{args:t}:{}},i.signal);return clearTimeout(s),{status:o?.status??"ok",message:o?.message,options:o?.options,data:o?.data}}catch(o){clearTimeout(s);const n=o instanceof Error?o.message:String(o);if(o?.code===-32601)throw this._supportsCommandsExecute=!1,o;return{status:"failed",message:n}}}handlePermissionRequest(e,t){const i=t,s=i?.toolCall??{},o=String(e),n=Array.isArray(i?.options)?i.options:[];this.pendingPermissions.set(o,{rpcId:e,options:n});const r=s.title||s.kind||"permission",d=s.toolCallId||o,f=s.title||"",w={type:c.PermissionRequest,requestId:o,toolName:r,toolInput:f||d,sessionId:this.acpSessionId,permissionRequest:{requestId:o,toolCallId:d,toolName:r,toolTitle:f,options:n,rawParams:t}};this.emit("event",w)}matchAvailableMode(e){const t=e.toLowerCase();for(const i of this.availableModes)if(i.id.toLowerCase()===t||i.name.toLowerCase()===t)return i.id;return""}pickPermissionOptionId(e,t){if(t.length===0)return"";if(e==="deny"){for(const s of t)if(s.kind==="reject_once"||s.kind==="reject_always")return s.optionId;for(const s of t)if(s.kind.toLowerCase().includes("reject")||s.kind.toLowerCase().includes("deny"))return s.optionId;for(const s of t)if(s.name.toLowerCase().includes("reject")||s.name.toLowerCase().includes("deny"))return s.optionId;return t[t.length-1].optionId}const i=e==="allow-always"?"allow_always":e==="allow-once"?"allow_once":null;if(i){for(const s of t)if(s.kind===i)return s.optionId}for(const s of t)if(s.kind.toLowerCase().includes("allow"))return s.optionId;for(const s of t)if(s.name.toLowerCase().includes("allow"))return s.optionId;return t[0].optionId}buildPermissionResult(e,t){return e==="deny"?t?{outcome:{outcome:"selected",optionId:t}}:{outcome:{outcome:"cancelled"}}:t?{outcome:{outcome:"selected",optionId:t}}:{outcome:{outcome:"cancelled"}}}}export{h as AcpAuthRequiredError,u as AcpClient,p as isAuthRequiredError};
1
+ import{EventEmitter as S}from"events";import{log as l}from"../core/log/index.js";import{AgentEventType as c}from"../types/events.js";import{mapSessionUpdate as M}from"./event-mapper.js";class h extends Error{authMethods;constructor(e){super("ACP authentication required"),this.name="AcpAuthRequiredError",this.authMethods=e}}function p(a){if(!a||typeof a!="object")return!1;const e=a;return e.code===-32e3?!0:e.code===-32603&&e.data?.details?/\b(401|token\s*expired|access\s*token)\b/i.test(e.data.details):!1}function m(a){return!a||typeof a!="object"?[{id:"oauth"}]:a.data?.authMethods??[{id:"oauth"}]}class u extends S{acpSessionId="";alive=!1;pendingPermissions=new Map;availableModes=[];availableModels=[];currentMode="";currentModel="";listSupported=!1;loadSupported=!1;_supportsCommandsExecute=!1;_availableCommands=[];transport;settleTimer=null;static SETTLE_MS=3e3;pendingToolCallIds=new Set;settleSuppressedSince=0;static SETTLE_SUPPRESS_MAX_MS=900*1e3;constructor(){super(),this.transport=null}get sessionId(){return this.acpSessionId}get isAlive(){return this.alive}get modes(){return[...this.availableModes]}get mode(){return this.currentMode}get models(){return[...this.availableModels]}get model(){return this.currentModel}get sessionOptions(){return{modes:[...this.availableModes],currentModeId:this.currentMode,models:[...this.availableModels],currentModelId:this.currentModel}}get supportsCommandsExecute(){return this._supportsCommandsExecute}get availableCommands(){return[...this._availableCommands]}async connect(e){this.transport=e.transport,this.transport.on("close",()=>{this.alive&&(this.alive=!1,this.emit("session-lost"))}),this.transport.setHandlers((n,r)=>{n==="session/update"?this.handleSessionUpdate(r):n==="_kiro.dev/metadata"?this.handleKiroMetadata(r):n==="_kiro.dev/commands/available"?this.handleCommandsAvailable(r):n==="_kiro.dev/compaction/status"?this.emit("compactionStatus",r):n==="_kiro.dev/clear/status"&&this.emit("clearStatus",r)},(n,r,d)=>{n==="session/request_permission"?this.handlePermissionRequest(r,d):n.startsWith("cursor/")?this.transport.respondSuccess(r,{}).catch(()=>{}):this.transport.respondError(r,-32601,"method not implemented").catch(()=>{})});const t=await this.initialize();this.listSupported=!!t.agentCapabilities?.sessionCapabilities?.list,this.loadSupported=!!t.agentCapabilities?.loadSession;const i=t.agentCapabilities??{};if(this._supportsCommandsExecute=!!(i.extensions?.["_kiro.dev/commands"]||i.commands),e.authMethod)try{await this.transport.call("authenticate",{methodId:e.authMethod})}catch(n){throw p(n)?new h(m(n)):n}const s=e.sessionId&&e.sessionId!=="__continue__";let o=!1;if(s){if(!this.loadSupported)throw new Error(`session/load not supported by agent, cannot resume session ${e.sessionId}`);try{await this.loadSession(e.sessionId,e)&&(o=!0)}catch(n){throw p(n)?new h(m(n)):n}if(!o)throw new Error(`session/load failed for session ${e.sessionId}`)}else try{await this.newSession(e)}catch(n){throw p(n)?new h(m(n)):n}e.initialMode&&await this.setLiveMode(e.initialMode).catch(()=>{}),e.initialModel&&await this.setModel(e.initialModel).catch(()=>{}),this.alive=!0}async initialize(){return await this.transport.call("initialize",{protocolVersion:1,clientCapabilities:{fs:{readTextFile:!1,writeTextFile:!1},terminal:!1},clientInfo:{name:"grix-connector-acp",version:"0.2.0"}})}buildMcpEntries(e){return(e??[]).map(t=>{const i={name:t.name,command:t.command};return t.args&&(i.args=t.args),t.env&&(i.env=Object.entries(t.env).map(([s,o])=>({name:s,value:o}))),i})}async newSession(e){const t=this.buildMcpEntries(e.mcpServers),i={cwd:e.cwd||process.cwd(),mcpServers:t};e.additionalDirectories&&e.additionalDirectories.length>0&&(i.additionalDirectories=e.additionalDirectories);const s=await this.transport.call("session/new",i);if(!s?.sessionId)throw new Error("session/new returned empty sessionId");this.acpSessionId=s.sessionId,this.absorbModes(s.modes),this.absorbModels(s.models)}async loadSession(e,t){const i=this.buildMcpEntries(t.mcpServers),s={sessionId:e,cwd:t.cwd||process.cwd(),mcpServers:i};t.additionalDirectories&&t.additionalDirectories.length>0&&(s.additionalDirectories=t.additionalDirectories);const o=await this.transport.call("session/load",s);return o?.sessionId?(this.acpSessionId=o.sessionId,this.absorbModes(o.modes),this.absorbModels(o.models),!0):o&&(o.modes||o.models)?(this.acpSessionId=e,this.absorbModes(o.modes),this.absorbModels(o.models),!0):(this.acpSessionId=e,!0)}absorbModes(e){e?.availableModes?.length&&(this.availableModes=[...e.availableModes],e.currentModeId&&(this.currentMode=e.currentModeId))}absorbModels(e){e?.availableModels?.length&&(this.availableModels=[...e.availableModels],e.currentModelId&&(this.currentModel=e.currentModelId))}async send(e,t,i){if(!this.alive)throw new Error("session not active");if(!this.acpSessionId)throw new Error("no agent session id");const s=[{type:"text",text:e}];if(t)for(const o of t)s.push({type:"image",data:o.data.toString("base64"),mimeType:o.mimeType});this.pendingToolCallIds.clear(),this.settleSuppressedSince=0,await this.transport.call("session/prompt",{sessionId:this.acpSessionId,prompt:s,...this.currentModel?{modelId:this.currentModel}:{}}),this.scheduleSettledResult()}scheduleSettledResult(){this.settleTimer&&clearTimeout(this.settleTimer),this.settleTimer=setTimeout(()=>{if(this.settleTimer=null,!!this.alive){if(this.pendingToolCallIds.size>0){if(this.settleSuppressedSince===0&&(this.settleSuppressedSince=Date.now()),Date.now()-this.settleSuppressedSince<u.SETTLE_SUPPRESS_MAX_MS){l.info("acp-client",`settle suppressed: ${this.pendingToolCallIds.size} pending tool call(s) for session ${this.acpSessionId}`),this.scheduleSettledResult();return}l.warn("acp-client",`settle suppression exceeded ${u.SETTLE_SUPPRESS_MAX_MS/6e4}min with ${this.pendingToolCallIds.size} pending tool call(s), emitting Result anyway`)}this.settleSuppressedSince=0,l.info("acp-client",`settle timer fired, emitting Result for session ${this.acpSessionId}`),this.emit("event",{type:c.Result,sessionId:this.acpSessionId,done:!0})}},u.SETTLE_MS),this.settleTimer.unref()}clearSettleTimer(){this.settleTimer&&(clearTimeout(this.settleTimer),this.settleTimer=null),this.settleSuppressedSince=0}async cancel(){if(this.acpSessionId){this.pendingToolCallIds.clear(),this.settleSuppressedSince=0;try{await this.transport.notify("session/cancel",{sessionId:this.acpSessionId})}catch{}}}async authenticate(e){await this.transport.call("authenticate",{methodId:e})}async respondPermission(e,t){const i=this.pendingPermissions.get(e);if(!i)throw new Error(`unknown permission request: ${e}`);this.pendingPermissions.delete(e);const s=this.pickPermissionOptionId(t.behavior,i.options),o=this.buildPermissionResult(t.behavior,s);await this.transport.respondSuccess(i.rpcId,o)}async ping(e=1e4){if(!this.alive)return!1;try{const t=new AbortController,i=setTimeout(()=>t.abort(),e);return await this.transport.call("session/list",{},t.signal),clearTimeout(i),!0}catch(t){return t?.code===-32601}}async setLiveMode(e){if(!this.acpSessionId)return l.warn("acp-client",`setLiveMode("${e}") skipped: no active session`),!1;const t=this.matchAvailableMode(e);if(!t)return l.warn("acp-client",`setLiveMode("${e}") failed: mode not found in available [${this.availableModes.map(i=>i.id).join(",")}]`),!1;try{const i=new AbortController,s=setTimeout(()=>i.abort(),8e3);return await this.transport.call("session/set_mode",{sessionId:this.acpSessionId,modeId:t},i.signal),clearTimeout(s),this.currentMode=t,!0}catch(i){return l.warn("acp-client",`setLiveMode("${t}") RPC failed: ${i instanceof Error?i.message:i}`),!1}}async setModel(e){if(!this.acpSessionId)return l.warn("acp-client",`setModel("${e}") skipped: no active session`),!1;try{const t=new AbortController,i=setTimeout(()=>t.abort(),8e3);return await this.transport.call("session/set_model",{sessionId:this.acpSessionId,modelId:e},t.signal),clearTimeout(i),this.currentModel=e,!0}catch(t){return l.warn("acp-client",`setModel("${e}") RPC failed: ${t instanceof Error?t.message:t}`),!1}}handleSessionUpdate(e){this.emit("activity");const t=e?.update?.sessionUpdate,i=t==="usage_update";if(t==="tool_call"||t==="tool_call_update"){const o=e?.update??{},n=String(o.toolCallId??""),r=String(o.status??"").toLowerCase().trim();n&&(r==="completed"||r==="failed"?this.pendingToolCallIds.delete(n):t==="tool_call"&&this.pendingToolCallIds.add(n))}this.settleTimer&&!i&&this.scheduleSettledResult();const s=M(this.acpSessionId,e);for(const o of s)o.sessionId||(o.sessionId=this.acpSessionId),o.type===c.Result&&(this.pendingToolCallIds.clear(),this.settleTimer&&this.clearSettleTimer()),this.emit("event",o)}handleKiroMetadata(e){const i=e?.contextUsagePercentage;typeof i!="number"||!Number.isFinite(i)||this.emit("event",{type:c.ContextWindowUpdate,sessionId:this.acpSessionId,contextWindow:{usedPercentage:Math.min(100,Math.max(0,i))}})}handleCommandsAvailable(e){const t=e,i=Array.isArray(t?.commands)?t.commands:[];this._availableCommands=i.map(s=>({name:String(s.name??""),description:s.description?String(s.description):void 0,args:s.args?String(s.args):void 0})),this._supportsCommandsExecute=!0,this.emit("commandsAvailable",this._availableCommands)}async executeCommand(e,t){if(!this.alive)throw new Error("session not active");if(!this.acpSessionId)throw new Error("no agent session id");const i=new AbortController,s=setTimeout(()=>i.abort(),2e4);try{const o=await this.transport.call("_kiro.dev/commands/execute",{sessionId:this.acpSessionId,command:e,...t?{args:t}:{}},i.signal);return clearTimeout(s),{status:o?.status??"ok",message:o?.message,options:o?.options,data:o?.data}}catch(o){clearTimeout(s);const n=o instanceof Error?o.message:String(o);if(o?.code===-32601)throw this._supportsCommandsExecute=!1,o;return{status:"failed",message:n}}}handlePermissionRequest(e,t){const i=t,s=i?.toolCall??{},o=String(e),n=Array.isArray(i?.options)?i.options:[];this.pendingPermissions.set(o,{rpcId:e,options:n});const r=s.title||s.kind||"permission",d=s.toolCallId||o,f=s.title||"",w={type:c.PermissionRequest,requestId:o,toolName:r,toolInput:f||d,sessionId:this.acpSessionId,permissionRequest:{requestId:o,toolCallId:d,toolName:r,toolTitle:f,options:n,rawParams:t}};this.emit("event",w)}matchAvailableMode(e){const t=e.toLowerCase();for(const i of this.availableModes)if(i.id.toLowerCase()===t||i.name.toLowerCase()===t)return i.id;return""}pickPermissionOptionId(e,t){if(t.length===0)return"";if(e==="deny"){for(const s of t)if(s.kind==="reject_once"||s.kind==="reject_always")return s.optionId;for(const s of t)if(s.kind.toLowerCase().includes("reject")||s.kind.toLowerCase().includes("deny"))return s.optionId;for(const s of t)if(s.name.toLowerCase().includes("reject")||s.name.toLowerCase().includes("deny"))return s.optionId;return t[t.length-1].optionId}const i=e==="allow-always"?"allow_always":e==="allow-once"?"allow_once":null;if(i){for(const s of t)if(s.kind===i)return s.optionId}for(const s of t)if(s.kind.toLowerCase().includes("allow"))return s.optionId;for(const s of t)if(s.name.toLowerCase().includes("allow"))return s.optionId;return t[0].optionId}buildPermissionResult(e,t){return e==="deny"?t?{outcome:{outcome:"selected",optionId:t}}:{outcome:{outcome:"cancelled"}}:t?{outcome:{outcome:"selected",optionId:t}}:{outcome:{outcome:"cancelled"}}}}export{h as AcpAuthRequiredError,u as AcpClient,p as isAuthRequiredError};
@@ -2265,11 +2265,11 @@ var require_extract_zip = __commonJS({
2265
2265
  var { createWriteStream: createWriteStream2, promises: fs } = __require("fs");
2266
2266
  var getStream = require_get_stream();
2267
2267
  var path7 = __require("path");
2268
- var { promisify } = __require("util");
2268
+ var { promisify: promisify2 } = __require("util");
2269
2269
  var stream = __require("stream");
2270
2270
  var yauzl = require_yauzl();
2271
- var openZip = promisify(yauzl.open);
2272
- var pipeline = promisify(stream.pipeline);
2271
+ var openZip = promisify2(yauzl.open);
2272
+ var pipeline = promisify2(stream.pipeline);
2273
2273
  var Extractor = class {
2274
2274
  constructor(zipPath, opts) {
2275
2275
  this.zipPath = zipPath;
@@ -2351,7 +2351,7 @@ var require_extract_zip = __commonJS({
2351
2351
  await fs.mkdir(destDir, mkdirOptions);
2352
2352
  if (isDir) return;
2353
2353
  debug("opening read stream", dest);
2354
- const readStream = await promisify(this.zipfile.openReadStream.bind(this.zipfile))(entry);
2354
+ const readStream = await promisify2(this.zipfile.openReadStream.bind(this.zipfile))(entry);
2355
2355
  if (symlink) {
2356
2356
  const link = await getStream(readStream);
2357
2357
  debug("creating symlink", link, dest);
@@ -3104,13 +3104,110 @@ function getAibotRuntime() {
3104
3104
  return runtime;
3105
3105
  }
3106
3106
 
3107
+ // src/openclaw/gateway-provider.ts
3108
+ import { execFile } from "node:child_process";
3109
+ import { readFile, writeFile as writeFile2, mkdir as mkdir2, unlink as unlink2 } from "node:fs/promises";
3110
+ import { existsSync } from "node:fs";
3111
+ import { homedir as homedir4 } from "node:os";
3112
+ import { dirname as dirname2, join as join3 } from "node:path";
3113
+ import { promisify } from "node:util";
3114
+ var execFileAsync = promisify(execFile);
3115
+ var CLI_TIMEOUT_MS = 3e4;
3116
+ var GRIX_PROVIDER_ID = "grix";
3117
+ function stateDir() {
3118
+ const explicit = process.env.OPENCLAW_STATE_DIR?.trim();
3119
+ if (explicit) return explicit;
3120
+ const cfg = process.env.OPENCLAW_CONFIG_PATH?.trim();
3121
+ if (cfg) return dirname2(cfg);
3122
+ return join3(homedir4(), ".openclaw");
3123
+ }
3124
+ function sidecarPath() {
3125
+ return join3(stateDir(), ".grix-relay-state.json");
3126
+ }
3127
+ async function runOpenClaw(args, stdin) {
3128
+ const child = execFileAsync("openclaw", args, { timeout: CLI_TIMEOUT_MS });
3129
+ child.child.stdin?.end(stdin ?? "");
3130
+ const { stdout } = await child;
3131
+ return stdout;
3132
+ }
3133
+ function configFilePath() {
3134
+ const explicit = process.env.OPENCLAW_CONFIG_PATH?.trim();
3135
+ if (explicit) return explicit.startsWith("~") ? join3(homedir4(), explicit.slice(1)) : explicit;
3136
+ return join3(homedir4(), ".openclaw", "openclaw.json");
3137
+ }
3138
+ async function readPreviousPrimary() {
3139
+ const file = configFilePath();
3140
+ if (!existsSync(file)) return void 0;
3141
+ try {
3142
+ const raw = JSON.parse(await readFile(file, "utf8"));
3143
+ const primary = raw?.agents?.defaults?.model?.primary;
3144
+ return typeof primary === "string" && primary.trim() ? primary.trim() : void 0;
3145
+ } catch {
3146
+ return void 0;
3147
+ }
3148
+ }
3149
+ async function applyOpenClawGatewayProvider(provider) {
3150
+ const baseUrl = provider.baseUrl?.trim();
3151
+ const apiKey = provider.apiKey?.trim();
3152
+ const model = provider.model?.trim();
3153
+ if (!baseUrl || !apiKey || !model) {
3154
+ throw new Error("gateway provider requires base_url, api_key and model");
3155
+ }
3156
+ const sidecar = sidecarPath();
3157
+ if (!existsSync(sidecar)) {
3158
+ const previousPrimary = await readPreviousPrimary();
3159
+ await mkdir2(dirname2(sidecar), { recursive: true });
3160
+ await writeFile2(
3161
+ sidecar,
3162
+ JSON.stringify({ previousPrimary: previousPrimary ?? null }, null, 2),
3163
+ { encoding: "utf8", mode: 384 }
3164
+ );
3165
+ }
3166
+ const patch = {
3167
+ models: {
3168
+ providers: {
3169
+ [GRIX_PROVIDER_ID]: {
3170
+ baseUrl,
3171
+ api: "openai-completions",
3172
+ auth: "api-key",
3173
+ apiKey,
3174
+ models: [{ id: model, name: model }]
3175
+ }
3176
+ }
3177
+ },
3178
+ agents: { defaults: { model: { primary: `${GRIX_PROVIDER_ID}/${model}` } } }
3179
+ };
3180
+ await runOpenClaw(["config", "patch", "--stdin"], JSON.stringify(patch));
3181
+ }
3182
+ async function clearOpenClawGatewayProvider() {
3183
+ const sidecar = sidecarPath();
3184
+ let previousPrimary = null;
3185
+ if (existsSync(sidecar)) {
3186
+ try {
3187
+ previousPrimary = JSON.parse(await readFile(sidecar, "utf8")).previousPrimary ?? null;
3188
+ } catch {
3189
+ previousPrimary = null;
3190
+ }
3191
+ }
3192
+ const patch = {
3193
+ models: { providers: { [GRIX_PROVIDER_ID]: null } }
3194
+ };
3195
+ if (previousPrimary) {
3196
+ patch.agents = { defaults: { model: { primary: previousPrimary } } };
3197
+ }
3198
+ await runOpenClaw(["config", "patch", "--stdin"], JSON.stringify(patch));
3199
+ await unlink2(sidecar).catch(() => void 0);
3200
+ return true;
3201
+ }
3202
+
3107
3203
  // src/openclaw/local-actions.ts
3108
3204
  var STABLE_LOCAL_ACTION_TYPES = [
3109
3205
  "exec_approve",
3110
3206
  "exec_reject",
3111
3207
  "file_list",
3112
3208
  "create_folder",
3113
- "get_session_usage"
3209
+ "get_session_usage",
3210
+ "configure_gateway_provider"
3114
3211
  ];
3115
3212
  function readStringParam(params, key) {
3116
3213
  const value = String(params[key] ?? "").trim();
@@ -3223,6 +3320,50 @@ async function handleExecResolutionAction(params) {
3223
3320
  );
3224
3321
  }
3225
3322
  }
3323
+ async function handleConfigureGatewayProviderLocalAction(payload) {
3324
+ const actionID = String(payload.action_id ?? "").trim() || "unknown";
3325
+ const params = payload.params ?? {};
3326
+ const apiKey = String(params.api_key ?? "").trim();
3327
+ const baseUrl = String(params.openai_base_url ?? "").trim();
3328
+ const model = String(params.model ?? "").trim();
3329
+ const disable = params.disable === true;
3330
+ try {
3331
+ if (disable || !apiKey) {
3332
+ await clearOpenClawGatewayProvider();
3333
+ return { action_id: actionID, status: "success", result: { relay: "disabled" } };
3334
+ }
3335
+ if (!baseUrl) {
3336
+ return {
3337
+ action_id: actionID,
3338
+ status: "failed",
3339
+ error_code: "missing_base_url",
3340
+ error_msg: "openai_base_url is required to enable Grix relay"
3341
+ };
3342
+ }
3343
+ if (!model) {
3344
+ return {
3345
+ action_id: actionID,
3346
+ status: "failed",
3347
+ error_code: "missing_model",
3348
+ error_msg: "model is required for openclaw (native provider config needs a model name)"
3349
+ };
3350
+ }
3351
+ await applyOpenClawGatewayProvider({ baseUrl, apiKey, model });
3352
+ return {
3353
+ action_id: actionID,
3354
+ status: "success",
3355
+ result: { relay: "enabled", model, restart_required: true }
3356
+ };
3357
+ } catch (err) {
3358
+ return {
3359
+ action_id: actionID,
3360
+ status: "failed",
3361
+ error_code: "config_write_failed",
3362
+ // 绝不把 api_key 带进错误信息。
3363
+ error_msg: err instanceof Error ? err.message : String(err)
3364
+ };
3365
+ }
3366
+ }
3226
3367
  async function handleStableLocalAction(params) {
3227
3368
  const actionID = String(params.payload.action_id ?? "").trim() || "unknown";
3228
3369
  const actionType = String(params.payload.action_type ?? "").trim();
@@ -3247,6 +3388,8 @@ async function handleStableLocalAction(params) {
3247
3388
  return handleCreateFolderLocalAction(params.payload);
3248
3389
  case "get_session_usage":
3249
3390
  return handleGetSessionUsageLocalAction(params.payload);
3391
+ case "configure_gateway_provider":
3392
+ return handleConfigureGatewayProviderLocalAction(params.payload);
3250
3393
  default:
3251
3394
  return unsupportedResult(actionID, actionType);
3252
3395
  }
@@ -3326,9 +3469,9 @@ async function handleGetSessionUsageLocalAction(payload) {
3326
3469
  }
3327
3470
 
3328
3471
  // src/openclaw/exec-command.ts
3329
- import { readdirSync, readFileSync, existsSync } from "node:fs";
3330
- import { join as join3, dirname as dirname2 } from "node:path";
3331
- import { homedir as homedir4 } from "node:os";
3472
+ import { readdirSync, readFileSync, existsSync as existsSync2 } from "node:fs";
3473
+ import { join as join4, dirname as dirname3 } from "node:path";
3474
+ import { homedir as homedir5 } from "node:os";
3332
3475
  import { fileURLToPath } from "node:url";
3333
3476
  function parseExecCommand(text) {
3334
3477
  const tokens = String(text ?? "").trim().split(/\s+/);
@@ -3356,13 +3499,13 @@ function parseSkillFrontmatter(content) {
3356
3499
  return { name, description };
3357
3500
  }
3358
3501
  function scanSkillDir(baseDir, source) {
3359
- if (!existsSync(baseDir)) return [];
3502
+ if (!existsSync2(baseDir)) return [];
3360
3503
  const results = [];
3361
3504
  try {
3362
3505
  for (const entry of readdirSync(baseDir, { withFileTypes: true })) {
3363
3506
  if (!entry.isDirectory() || entry.name.startsWith(".")) continue;
3364
- const skillFile = join3(baseDir, entry.name, "SKILL.md");
3365
- if (!existsSync(skillFile)) continue;
3507
+ const skillFile = join4(baseDir, entry.name, "SKILL.md");
3508
+ if (!existsSync2(skillFile)) continue;
3366
3509
  try {
3367
3510
  const parsed = parseSkillFrontmatter(readFileSync(skillFile, "utf-8"));
3368
3511
  if (parsed.name) results.push({ name: parsed.name, description: parsed.description, source });
@@ -3375,10 +3518,10 @@ function scanSkillDir(baseDir, source) {
3375
3518
  }
3376
3519
  function scanOpenClawSkills() {
3377
3520
  const results = [];
3378
- const thisDir = dirname2(fileURLToPath(import.meta.url));
3379
- const pluginSkills = join3(thisDir, "..", "skills");
3521
+ const thisDir = dirname3(fileURLToPath(import.meta.url));
3522
+ const pluginSkills = join4(thisDir, "..", "skills");
3380
3523
  results.push(...scanSkillDir(pluginSkills, "plugin"));
3381
- results.push(...scanSkillDir(join3(homedir4(), ".openclaw", "skills"), "global"));
3524
+ results.push(...scanSkillDir(join4(homedir5(), ".openclaw", "skills"), "global"));
3382
3525
  return results;
3383
3526
  }
3384
3527
  function handleSkillsCommand() {
@@ -3394,7 +3537,7 @@ ${lines.join("\n\n")}`;
3394
3537
  }
3395
3538
 
3396
3539
  // src/openclaw/shared/file-serve/tailnet-ip.ts
3397
- import { execFile } from "node:child_process";
3540
+ import { execFile as execFile2 } from "node:child_process";
3398
3541
  import * as os5 from "node:os";
3399
3542
  function isTailnetIPv4(addr) {
3400
3543
  const parts = addr.split(".");
@@ -3406,7 +3549,7 @@ function isTailnetIPv4(addr) {
3406
3549
  }
3407
3550
  function detectViaCLI() {
3408
3551
  return new Promise((resolve3) => {
3409
- execFile("tailscale", ["ip", "-4"], { timeout: 3e3 }, (err, stdout) => {
3552
+ execFile2("tailscale", ["ip", "-4"], { timeout: 3e3 }, (err, stdout) => {
3410
3553
  if (err) {
3411
3554
  resolve3(void 0);
3412
3555
  return;
@@ -5559,13 +5702,13 @@ var grixExecApprovalAdapter = {
5559
5702
  // src/openclaw/log-rotation.ts
5560
5703
  import {
5561
5704
  appendFileSync,
5562
- existsSync as existsSync2,
5705
+ existsSync as existsSync3,
5563
5706
  mkdirSync,
5564
5707
  renameSync,
5565
5708
  rmSync,
5566
5709
  statSync
5567
5710
  } from "node:fs";
5568
- import { dirname as dirname3 } from "node:path";
5711
+ import { dirname as dirname4 } from "node:path";
5569
5712
  function rotationPath(filePath, index) {
5570
5713
  return `${filePath}.${index}`;
5571
5714
  }
@@ -5573,17 +5716,17 @@ function rotateLogFileIfNeededSync(filePath, incomingBytes, options) {
5573
5716
  if (options.maxBytes <= 0 || options.maxFiles <= 0) {
5574
5717
  return false;
5575
5718
  }
5576
- if (!existsSync2(filePath)) {
5719
+ if (!existsSync3(filePath)) {
5577
5720
  return false;
5578
5721
  }
5579
5722
  const currentBytes = statSync(filePath).size;
5580
5723
  if (currentBytes + Math.max(0, incomingBytes) <= options.maxBytes) {
5581
5724
  return false;
5582
5725
  }
5583
- mkdirSync(dirname3(filePath), { recursive: true });
5726
+ mkdirSync(dirname4(filePath), { recursive: true });
5584
5727
  for (let index = options.maxFiles; index >= 1; index -= 1) {
5585
5728
  const sourcePath = index === 1 ? filePath : rotationPath(filePath, index - 1);
5586
- if (!existsSync2(sourcePath)) {
5729
+ if (!existsSync3(sourcePath)) {
5587
5730
  continue;
5588
5731
  }
5589
5732
  const targetPath = rotationPath(filePath, index);
@@ -5593,22 +5736,22 @@ function rotateLogFileIfNeededSync(filePath, incomingBytes, options) {
5593
5736
  return true;
5594
5737
  }
5595
5738
  function appendRotatedLogLineSync(filePath, line, options) {
5596
- mkdirSync(dirname3(filePath), { recursive: true });
5739
+ mkdirSync(dirname4(filePath), { recursive: true });
5597
5740
  rotateLogFileIfNeededSync(filePath, Buffer.byteLength(line), options);
5598
5741
  appendFileSync(filePath, line, "utf8");
5599
5742
  }
5600
5743
 
5601
5744
  // src/openclaw/plugin-logger.ts
5602
- import { homedir as homedir5 } from "node:os";
5603
- import { join as join4, dirname as dirname4 } from "node:path";
5604
- var BASE_DIR = process.env.GRIX_CONNECTOR_HOME ? process.env.GRIX_CONNECTOR_HOME : join4(homedir5(), ".grix");
5745
+ import { homedir as homedir6 } from "node:os";
5746
+ import { join as join5, dirname as dirname5 } from "node:path";
5747
+ var BASE_DIR = process.env.GRIX_CONNECTOR_HOME ? process.env.GRIX_CONNECTOR_HOME : join5(homedir6(), ".grix");
5605
5748
  var LOG_ROTATION = {
5606
5749
  maxBytes: 10 * 1024 * 1024,
5607
5750
  maxFiles: 5
5608
5751
  };
5609
5752
  var pendingConversationWrites = /* @__PURE__ */ new Map();
5610
5753
  function appendServiceLog(target, line) {
5611
- const filePath = join4(
5754
+ const filePath = join5(
5612
5755
  BASE_DIR,
5613
5756
  "service",
5614
5757
  target === "out" ? "out.log" : "err.log"
@@ -5630,7 +5773,7 @@ function appendConversationLog(filePath, line) {
5630
5773
  const previous = pendingConversationWrites.get(filePath) ?? Promise.resolve();
5631
5774
  const next = previous.catch(() => {
5632
5775
  }).then(async () => {
5633
- await mkdir(dirname4(filePath), { recursive: true });
5776
+ await mkdir(dirname5(filePath), { recursive: true });
5634
5777
  rotateLogFileIfNeededSync(filePath, Buffer.byteLength(line), LOG_ROTATION);
5635
5778
  await appendFile(filePath, line, "utf8");
5636
5779
  });
@@ -5643,7 +5786,7 @@ function appendConversationLog(filePath, line) {
5643
5786
  });
5644
5787
  }
5645
5788
  function logConversation(entry) {
5646
- const filePath = join4(
5789
+ const filePath = join5(
5647
5790
  BASE_DIR,
5648
5791
  "log",
5649
5792
  "sessions",
@@ -6011,36 +6154,36 @@ function buildAibotTextSendPlan(params) {
6011
6154
  }
6012
6155
 
6013
6156
  // src/core/log/logger.ts
6014
- import { createWriteStream, mkdirSync as mkdirSync2, existsSync as existsSync3, readdirSync as readdirSync2, statSync as statSync2, unlinkSync } from "node:fs";
6015
- import { join as join6 } from "node:path";
6157
+ import { createWriteStream, mkdirSync as mkdirSync2, existsSync as existsSync4, readdirSync as readdirSync2, statSync as statSync2, unlinkSync } from "node:fs";
6158
+ import { join as join7 } from "node:path";
6016
6159
 
6017
6160
  // src/core/config/paths.ts
6018
- import { join as join5 } from "node:path";
6019
- import { homedir as homedir6 } from "node:os";
6161
+ import { join as join6 } from "node:path";
6162
+ import { homedir as homedir7 } from "node:os";
6020
6163
  var GRIX_HOME_ENV = "GRIX_CONNECTOR_HOME";
6021
- var DEFAULT_GRIX_HOME = join5(homedir6(), ".grix");
6164
+ var DEFAULT_GRIX_HOME = join6(homedir7(), ".grix");
6022
6165
  function resolveRuntimePaths(runtimeDir) {
6023
6166
  const rootDir = runtimeDir ? runtimeDir : process.env[GRIX_HOME_ENV] ? process.env[GRIX_HOME_ENV] : DEFAULT_GRIX_HOME;
6024
6167
  return {
6025
6168
  rootDir,
6026
- configDir: join5(rootDir, "config"),
6027
- logDir: join5(rootDir, "log"),
6028
- dataDir: join5(rootDir, "data"),
6029
- serviceDir: join5(rootDir, "service"),
6030
- stateFile: join5(rootDir, "service.json"),
6031
- pidFile: join5(rootDir, "grix-connector.pid"),
6032
- daemonLockFile: join5(rootDir, "daemon.lock.json"),
6033
- daemonStatusFile: join5(rootDir, "daemon-status.json"),
6034
- stdoutLogFile: join5(rootDir, "service", "daemon.out.log"),
6035
- stderrLogFile: join5(rootDir, "service", "daemon.err.log"),
6036
- contextsDir: join5(rootDir, "data", "session-contexts"),
6037
- hookSignalsPath: join5(rootDir, "data", "hook-signals.json"),
6038
- hookSignalsLogPath: join5(rootDir, "log", "hook-signals.log"),
6039
- elicitationRequestsDir: join5(rootDir, "data", "elicitation-requests"),
6040
- eventStatesDir: join5(rootDir, "data", "event-states"),
6041
- questionRequestsDir: join5(rootDir, "data", "question-requests"),
6042
- permissionRequestsDir: join5(rootDir, "data", "permission-requests"),
6043
- agentGlobalConfigsFile: join5(rootDir, "data", "agent-global-configs.json")
6169
+ configDir: join6(rootDir, "config"),
6170
+ logDir: join6(rootDir, "log"),
6171
+ dataDir: join6(rootDir, "data"),
6172
+ serviceDir: join6(rootDir, "service"),
6173
+ stateFile: join6(rootDir, "service.json"),
6174
+ pidFile: join6(rootDir, "grix-connector.pid"),
6175
+ daemonLockFile: join6(rootDir, "daemon.lock.json"),
6176
+ daemonStatusFile: join6(rootDir, "daemon-status.json"),
6177
+ stdoutLogFile: join6(rootDir, "service", "daemon.out.log"),
6178
+ stderrLogFile: join6(rootDir, "service", "daemon.err.log"),
6179
+ contextsDir: join6(rootDir, "data", "session-contexts"),
6180
+ hookSignalsPath: join6(rootDir, "data", "hook-signals.json"),
6181
+ hookSignalsLogPath: join6(rootDir, "log", "hook-signals.log"),
6182
+ elicitationRequestsDir: join6(rootDir, "data", "elicitation-requests"),
6183
+ eventStatesDir: join6(rootDir, "data", "event-states"),
6184
+ questionRequestsDir: join6(rootDir, "data", "question-requests"),
6185
+ permissionRequestsDir: join6(rootDir, "data", "permission-requests"),
6186
+ agentGlobalConfigsFile: join6(rootDir, "data", "agent-global-configs.json")
6044
6187
  };
6045
6188
  }
6046
6189
 
@@ -6106,7 +6249,7 @@ function cleanupOldLogs() {
6106
6249
  }
6107
6250
  for (const name of entries2) {
6108
6251
  if (!name.startsWith("grix-connector-") || !name.includes(".log")) continue;
6109
- const full = join6(GRIX_PATHS.log, name);
6252
+ const full = join7(GRIX_PATHS.log, name);
6110
6253
  try {
6111
6254
  if (statSync2(full).mtimeMs < cutoff) unlinkSync(full);
6112
6255
  } catch {
@@ -6118,7 +6261,7 @@ function openLogStream(date) {
6118
6261
  logStream?.end();
6119
6262
  } catch {
6120
6263
  }
6121
- const logFile = join6(GRIX_PATHS.log, `grix-connector-${date}.log`);
6264
+ const logFile = join7(GRIX_PATHS.log, `grix-connector-${date}.log`);
6122
6265
  logStream = createWriteStream(logFile, { flags: "a" });
6123
6266
  currentLogDate = date;
6124
6267
  cleanupOldLogs();
@@ -10306,8 +10449,8 @@ function collectMissingParameters(request) {
10306
10449
  }
10307
10450
 
10308
10451
  // src/openclaw/egg/orchestrator.ts
10309
- import { join as join9 } from "node:path";
10310
- import { homedir as homedir7 } from "node:os";
10452
+ import { join as join10 } from "node:path";
10453
+ import { homedir as homedir8 } from "node:os";
10311
10454
 
10312
10455
  // src/openclaw/sdk-exec.ts
10313
10456
  function resolveOpenClawCliArgvPrefix2() {
@@ -10417,21 +10560,21 @@ async function downloadPackage(params) {
10417
10560
 
10418
10561
  // src/openclaw/egg/persona-installer.ts
10419
10562
  var import_extract_zip = __toESM(require_extract_zip(), 1);
10420
- import { join as join7 } from "node:path";
10563
+ import { join as join8 } from "node:path";
10421
10564
  import { tmpdir } from "node:os";
10422
10565
  var PERSONA_FILES = ["IDENTITY.md", "SOUL.md", "AGENTS.md"];
10423
10566
  var OPTIONAL_PERSONA_FILES = ["USER.md", "MEMORY.md"];
10424
10567
  var ALL_PERSONA_FILES = [...PERSONA_FILES, ...OPTIONAL_PERSONA_FILES];
10425
10568
  function getWorkspaceRoot(agentName, openclawHome) {
10426
- return join7(openclawHome, `workspace-${agentName}`);
10569
+ return join8(openclawHome, `workspace-${agentName}`);
10427
10570
  }
10428
10571
  async function ensureWorkspaceDir(workspaceRoot) {
10429
10572
  await mkdir(workspaceRoot, { recursive: true });
10430
10573
  }
10431
10574
  async function extractZipToTemp(buffer) {
10432
- const tmpDir = join7(tmpdir(), `egg-extract-${Date.now()}`);
10575
+ const tmpDir = join8(tmpdir(), `egg-extract-${Date.now()}`);
10433
10576
  await mkdir(tmpDir, { recursive: true });
10434
- const zipPath = join7(tmpDir, "package.zip");
10577
+ const zipPath = join8(tmpDir, "package.zip");
10435
10578
  await writeFile(zipPath, buffer);
10436
10579
  await (0, import_extract_zip.default)(zipPath, { dir: tmpDir });
10437
10580
  return tmpDir;
@@ -10441,7 +10584,7 @@ async function findPersonaFilesInDir(dir, prefix = "") {
10441
10584
  const entries2 = await listEntries(dir, { withFileTypes: true });
10442
10585
  for (const entry of entries2) {
10443
10586
  if (entry.name === "package.zip") continue;
10444
- const fullPath = join7(dir, entry.name);
10587
+ const fullPath = join8(dir, entry.name);
10445
10588
  const relativeName = prefix ? `${prefix}/${entry.name}` : entry.name;
10446
10589
  if (entry.isDirectory()) {
10447
10590
  const nested = await findPersonaFilesInDir(fullPath, relativeName);
@@ -10464,7 +10607,7 @@ async function installPersonaFromZip(params) {
10464
10607
  const personaFiles = await findPersonaFilesInDir(tmpDir);
10465
10608
  for (const [fileName, sourcePath] of personaFiles) {
10466
10609
  const content = await loadFile(sourcePath, "utf-8");
10467
- await writeFile(join7(workspaceRoot, fileName), content, "utf-8");
10610
+ await writeFile(join8(workspaceRoot, fileName), content, "utf-8");
10468
10611
  installedFiles.push(fileName);
10469
10612
  }
10470
10613
  await ensureMinimalPersonaFiles(workspaceRoot, installedFiles);
@@ -10479,13 +10622,13 @@ async function ensureMinimalPersonaFiles(workspaceRoot, existingFiles) {
10479
10622
  if (!existingFiles.includes(required)) {
10480
10623
  const content = `# ${required.replace(".md", "")}
10481
10624
  `;
10482
- await writeFile(join7(workspaceRoot, required), content, "utf-8");
10625
+ await writeFile(join8(workspaceRoot, required), content, "utf-8");
10483
10626
  }
10484
10627
  }
10485
10628
  }
10486
10629
 
10487
10630
  // src/openclaw/egg/local-binding.ts
10488
- import { join as join8 } from "node:path";
10631
+ import { join as join9 } from "node:path";
10489
10632
  var LocalBindingError = class extends Error {
10490
10633
  constructor(message) {
10491
10634
  super(`[egg:bind] ${message}`);
@@ -10586,8 +10729,8 @@ function buildAgentListEntry(params) {
10586
10729
  }
10587
10730
  async function runLocalBinding(params) {
10588
10731
  const { agentName, createdAgent, isMainAgent = false, openclawHome } = params;
10589
- const workspace = join8(openclawHome, `workspace-${agentName}`);
10590
- const agentDir = join8(openclawHome, "agents", agentName, "agent");
10732
+ const workspace = join9(openclawHome, `workspace-${agentName}`);
10733
+ const agentDir = join9(openclawHome, "agents", agentName, "agent");
10591
10734
  await mkdir(workspace, { recursive: true });
10592
10735
  await mkdir(agentDir, { recursive: true });
10593
10736
  const wsUrl = deriveWsUrl(createdAgent.api_endpoint);
@@ -10767,7 +10910,7 @@ function makeEmptySteps() {
10767
10910
  };
10768
10911
  }
10769
10912
  function resolveStateFilePath(installId) {
10770
- return join9(homedir7(), ".openclaw", "egg-installs", `${installId}.json`);
10913
+ return join10(homedir8(), ".openclaw", "egg-installs", `${installId}.json`);
10771
10914
  }
10772
10915
  async function readStateFile(filePath) {
10773
10916
  try {
@@ -10778,7 +10921,7 @@ async function readStateFile(filePath) {
10778
10921
  }
10779
10922
  }
10780
10923
  async function writeStateFile(filePath, state) {
10781
- await mkdir(join9(homedir7(), ".openclaw", "egg-installs"), { recursive: true });
10924
+ await mkdir(join10(homedir8(), ".openclaw", "egg-installs"), { recursive: true });
10782
10925
  state.updated_at = nowIso();
10783
10926
  await writeFile(filePath, `${JSON.stringify(state, null, 2)}
10784
10927
  `, "utf-8");
@@ -10907,7 +11050,7 @@ async function writeSoulIfProvided(request, workspaceRoot) {
10907
11050
  content = await loadFile(soulFile, "utf-8");
10908
11051
  }
10909
11052
  if (!content) return;
10910
- await writeFile(join9(workspaceRoot, "SOUL.md"), content, "utf-8");
11053
+ await writeFile(join10(workspaceRoot, "SOUL.md"), content, "utf-8");
10911
11054
  }
10912
11055
  function parseNumericId(value) {
10913
11056
  const normalized = cleanText2(value);
@@ -11294,8 +11437,8 @@ async function runEggOrchestrator(params) {
11294
11437
  errorCode: "create_agent_failed"
11295
11438
  });
11296
11439
  }
11297
- const openclawHome = join9(homedir7(), ".openclaw");
11298
- const workspaceRoot = join9(openclawHome, `workspace-${request.localAgentName}`);
11440
+ const openclawHome = join10(homedir8(), ".openclaw");
11441
+ const workspaceRoot = join10(openclawHome, `workspace-${request.localAgentName}`);
11299
11442
  let downloadedBuffer = null;
11300
11443
  if (state.steps.install.status !== "done") {
11301
11444
  try {
@@ -11635,10 +11778,10 @@ function createGrixRegisterTool(api, ctx) {
11635
11778
 
11636
11779
  // src/openclaw/skill-tools/grix-update-tool.ts
11637
11780
  import { tmpdir as tmpdir2 } from "node:os";
11638
- import { join as join10 } from "node:path";
11781
+ import { join as join11 } from "node:path";
11639
11782
 
11640
11783
  // src/openclaw/skill-tools/timed-file-lock.ts
11641
- import { dirname as dirname5 } from "node:path";
11784
+ import { dirname as dirname6 } from "node:path";
11642
11785
  function getErrorCode(err) {
11643
11786
  if (typeof err !== "object" || err === null || !("code" in err)) {
11644
11787
  return void 0;
@@ -11692,7 +11835,7 @@ async function readExistingLock(lockFilePath, ttlMs) {
11692
11835
  }
11693
11836
  async function tryAcquireTimedFileLock(options) {
11694
11837
  const now = options.now ?? Date.now;
11695
- await mkdir(dirname5(options.lockFilePath), { recursive: true });
11838
+ await mkdir(dirname6(options.lockFilePath), { recursive: true });
11696
11839
  for (let attempt = 0; attempt < 4; attempt += 1) {
11697
11840
  const createdAt = now();
11698
11841
  const expiresAt = createdAt + options.ttlMs;
@@ -11746,7 +11889,7 @@ function normalizeNonEmptyString2(value) {
11746
11889
  return typeof value === "string" && value.trim() ? value.trim() : void 0;
11747
11890
  }
11748
11891
  function resolveGrixUpdateLockFilePath(lockFilePath) {
11749
- return lockFilePath ?? join10(tmpdir2(), "grix-connector-update.lock");
11892
+ return lockFilePath ?? join11(tmpdir2(), "grix-connector-update.lock");
11750
11893
  }
11751
11894
  function createGrixUpdateTool(api, ctx, options = {}) {
11752
11895
  const delegatedTool = createDelegatedSkillTool({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "grix-connector",
3
- "version": "3.7.0",
3
+ "version": "3.8.0",
4
4
  "description": "Connect local AI coding agents (Claude, Codex, Gemini, Qwen, DeepSeek, Cursor, OpenCode, Pi, OpenHuman, Reasonix) to the Grix scheduling platform. Also serves as an OpenClaw plugin for Grix channel transport.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -21,7 +21,7 @@
21
21
  "scripts": {
22
22
  "postinstall": "node scripts/install-guardian.mjs",
23
23
  "prepublishOnly": "npm run build:all",
24
- "build": "npm run check:isolation && node -e \"require('fs').rmSync('dist/default-skills',{recursive:true,force:true})\" && tsc && node -e \"require('fs').cpSync('src/default-skills','dist/default-skills',{recursive:true,filter:s=>!s.endsWith('.ts')})\"",
24
+ "build": "npm run check:isolation && node -e \"require('fs').rmSync('dist/default-skills',{recursive:true,force:true})\" && tsc && node -e \"require('fs').cpSync('src/default-skills','dist/default-skills',{recursive:true,filter:s=>!s.endsWith('.ts')})\" && node -e \"require('fs').cpSync('src/core/proxy/hermes-profile-relay.py','dist/core/proxy/hermes-profile-relay.py')\"",
25
25
  "check:isolation": "node scripts/check-adapter-isolation.mjs",
26
26
  "build:plugin": "node scripts/build-plugin.mjs",
27
27
  "build:all": "npm run build && node scripts/minify-dist.mjs && npm run build:plugin",