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.
- package/dist/adapter/acp/acp-adapter.js +10 -10
- package/dist/adapter/codewhale/codewhale-adapter.js +1 -1
- package/dist/core/admin/admin-server.js +1 -1
- package/dist/core/installer/manual-guide.js +1 -1
- package/dist/core/installer/registry.js +1 -1
- package/dist/core/proxy/hermes-profile-relay.js +1 -0
- package/dist/core/proxy/hermes-profile-relay.py +492 -0
- package/dist/core/proxy/relay-credential-router.js +1 -0
- package/dist/grix.js +6 -6
- package/dist/mcp/stream-http/security.js +1 -1
- package/dist/protocol/acp-client.js +1 -1
- package/openclaw-plugin/index.js +217 -74
- package/package.json +2 -2
|
@@ -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};
|
package/openclaw-plugin/index.js
CHANGED
|
@@ -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 =
|
|
2272
|
-
var 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
|
|
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
|
|
3331
|
-
import { homedir as
|
|
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 (!
|
|
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 =
|
|
3365
|
-
if (!
|
|
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 =
|
|
3379
|
-
const pluginSkills =
|
|
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(
|
|
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
|
-
|
|
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
|
|
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
|
|
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 (!
|
|
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(
|
|
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 (!
|
|
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(
|
|
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
|
|
5603
|
-
import { join as
|
|
5604
|
-
var BASE_DIR = process.env.GRIX_CONNECTOR_HOME ? process.env.GRIX_CONNECTOR_HOME :
|
|
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 =
|
|
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(
|
|
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 =
|
|
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
|
|
6015
|
-
import { join as
|
|
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
|
|
6019
|
-
import { homedir as
|
|
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 =
|
|
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:
|
|
6027
|
-
logDir:
|
|
6028
|
-
dataDir:
|
|
6029
|
-
serviceDir:
|
|
6030
|
-
stateFile:
|
|
6031
|
-
pidFile:
|
|
6032
|
-
daemonLockFile:
|
|
6033
|
-
daemonStatusFile:
|
|
6034
|
-
stdoutLogFile:
|
|
6035
|
-
stderrLogFile:
|
|
6036
|
-
contextsDir:
|
|
6037
|
-
hookSignalsPath:
|
|
6038
|
-
hookSignalsLogPath:
|
|
6039
|
-
elicitationRequestsDir:
|
|
6040
|
-
eventStatesDir:
|
|
6041
|
-
questionRequestsDir:
|
|
6042
|
-
permissionRequestsDir:
|
|
6043
|
-
agentGlobalConfigsFile:
|
|
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 =
|
|
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 =
|
|
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
|
|
10310
|
-
import { homedir as
|
|
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
|
|
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
|
|
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 =
|
|
10575
|
+
const tmpDir = join8(tmpdir(), `egg-extract-${Date.now()}`);
|
|
10433
10576
|
await mkdir(tmpDir, { recursive: true });
|
|
10434
|
-
const zipPath =
|
|
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 =
|
|
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(
|
|
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(
|
|
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
|
|
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 =
|
|
10590
|
-
const agentDir =
|
|
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
|
|
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(
|
|
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(
|
|
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 =
|
|
11298
|
-
const workspaceRoot =
|
|
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
|
|
11781
|
+
import { join as join11 } from "node:path";
|
|
11639
11782
|
|
|
11640
11783
|
// src/openclaw/skill-tools/timed-file-lock.ts
|
|
11641
|
-
import { dirname as
|
|
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(
|
|
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 ??
|
|
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.
|
|
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",
|