grix-connector
Version:
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.
2 lines (1 loc) • 6.19 kB
JavaScript
import{log as l}from"../core/log/index.js";const v=2,E=3e3,C=h=>{const e=h.toLowerCase();return e.includes("claude channel listener not ready")||e.includes("notify port")||e.includes("mcp stdio server not available")||e.includes("mcp server startup failed")},y={claude:{announceComposing:!1,retriable:C,retryMax:v,retryDelayMs:E},codex:{announceComposing:!0,composingOptsOverridable:!0},codewhale:{announceComposing:!0,composingOptsOverridable:!0},cursor:{announceComposing:!1},pi:{announceComposing:!0,composingTtlMs:3e4,stopComposingOnError:!0},openhuman:{announceComposing:!0},opencode:{announceComposing:!0},agy:{announceComposing:!0},acp:{announceComposing:!0}},g=["claude","codex","cursor","acp","pi","openhuman","codewhale","opencode","agy"];class _{name;deferredClaudeEvents=new Map;deferredClaudeReplayRetries=new Map;deferredCodexEvents=new Map;deferredCursorEvents=new Map;deferredAcpEvents=new Map;deferredPiEvents=new Map;deferredOpenHumanEvents=new Map;deferredCodeWhaleEvents=new Map;deferredOpenCodeEvents=new Map;deferredAgyEvents=new Map;constructor(e){this.name=e}defer(e,r,t){if(!r)return;const n=this.getMap(e),d=n.get(r)??[];d.some(i=>i.event_id===t.event_id)||(l.info(this.name,`defer channel=${e} session_id=${r} event_id=${t.event_id} queue_len=${d.length}`),d.push(t),n.set(r,d))}deferClaudeEvent(e,r){this.defer("claude",e,r)}deferCodexEvent(e,r){this.defer("codex",e,r)}deferCursorEvent(e,r){this.defer("cursor",e,r)}deferAcpEvent(e,r){this.defer("acp",e,r)}deferPiEvent(e,r){this.defer("pi",e,r)}deferOpenHumanEvent(e,r){this.defer("openhuman",e,r)}deferCodeWhaleEvent(e,r){this.defer("codewhale",e,r)}deferOpenCodeEvent(e,r){this.defer("opencode",e,r)}deferAgyEvent(e,r){this.defer("agy",e,r)}async replayChannel(e,r,t,n={}){const d=this.getMap(e),i=d.get(r);if(!i||i.length===0)return;d.delete(r);const a=y[e];((a.composingOptsOverridable?n.announceComposing:void 0)??a.announceComposing)&&t.sendSessionComposing?.(r,!0,a.composingTtlMs?{ttlMs:a.composingTtlMs}:void 0);for(const s of i)try{t.captureEventRuntimeConfig(s),await t.deliverInboundEvent(s),this.deferredClaudeReplayRetries.delete(s.event_id)}catch(f){const p=f instanceof Error?f.message:String(f),u=this.deferredClaudeReplayRetries.get(s.event_id)??0;if(a.retriable?.(p)&&u<(a.retryMax??0)){this.deferredClaudeReplayRetries.set(s.event_id,u+1);const c=d.get(r)??[];c.some(o=>o.event_id===s.event_id)||(c.push(s),d.set(r,c)),l.warn(this.name,`replay retry ${u+1}/${a.retryMax} channel=${e} session_id=${r} event_id=${s.event_id} reason=${p}`),setTimeout(()=>{this.replayChannel(e,r,t,n).catch(o=>{l.warn(this.name,`replay async retry failed channel=${e} session_id=${r}: ${o instanceof Error?o.message:String(o)}`)})},a.retryDelayMs??0).unref();continue}this.deferredClaudeReplayRetries.delete(s.event_id),a.stopComposingOnError&&t.sendSessionComposing?.(r,!1),t.sendEventResult(s.event_id,"failed",p)}}async replayDeferredClaudeEvents(e,r){await this.replayChannel("claude",e,r)}async replayDeferredCodexEvents(e,r,t={}){await this.replayChannel("codex",e,r,t)}async replayDeferredCursorEvents(e,r,t={}){await this.replayChannel("cursor",e,r,t)}async replayDeferredPiEvents(e,r){await this.replayChannel("pi",e,r)}async replayDeferredOpenHumanEvents(e,r){await this.replayChannel("openhuman",e,r)}async replayDeferredOpenCodeEvents(e,r){await this.replayChannel("opencode",e,r)}async replayDeferredAgyEvents(e,r){await this.replayChannel("agy",e,r)}async replayDeferredAcpEvents(e,r){await this.replayChannel("acp",e,r)}async replayDeferredCodeWhaleEvents(e,r,t={}){await this.replayChannel("codewhale",e,r,t)}async release(e,r,t={}){for(const n of g)this.getMap(n).has(e)&&await this.replayChannel(n,e,r,t)}sendCodexDeferredReplayComposing(e,r){const t=this.deferredCodexEvents.get(e);!t||t.length===0||r.sendSessionComposing?.(e,!0,{ttlMs:12e4,activity:"preparing"})}sendCursorDeferredReplayComposing(e,r){const t=this.deferredCursorEvents.get(e);!t||t.length===0||r.sendSessionComposing?.(e,!0)}hasDeferred(e,r){return this.getMap(e).has(r)}getAllDeferredEvents(){return[...this.deferredClaudeEvents.values(),...this.deferredCodexEvents.values(),...this.deferredCursorEvents.values(),...this.deferredPiEvents.values(),...this.deferredAcpEvents.values(),...this.deferredOpenHumanEvents.values(),...this.deferredCodeWhaleEvents.values(),...this.deferredOpenCodeEvents.values(),...this.deferredAgyEvents.values()].flat()}clearAll(){this.deferredClaudeEvents.clear(),this.deferredClaudeReplayRetries.clear(),this.deferredCodexEvents.clear(),this.deferredCursorEvents.clear(),this.deferredPiEvents.clear(),this.deferredOpenHumanEvents.clear(),this.deferredCodeWhaleEvents.clear(),this.deferredOpenCodeEvents.clear(),this.deferredAgyEvents.clear(),this.deferredAcpEvents.clear()}removeEvent(e){for(const r of[this.deferredClaudeEvents,this.deferredCodexEvents,this.deferredCursorEvents,this.deferredAcpEvents,this.deferredPiEvents,this.deferredOpenHumanEvents,this.deferredCodeWhaleEvents,this.deferredOpenCodeEvents,this.deferredAgyEvents])for(const[t,n]of r.entries()){const d=n.findIndex(i=>i.event_id===e);if(d>=0)return n.splice(d,1),n.length===0&&r.delete(t),this.deferredClaudeReplayRetries.delete(e),l.info(this.name,`removeEvent event_id=${e} from deferred queue`),!0}return!1}clearSession(e){const r=this.deferredClaudeEvents.get(e)??[];for(const t of r)this.deferredClaudeReplayRetries.delete(t.event_id);this.deferredClaudeEvents.delete(e),this.deferredCodexEvents.delete(e),this.deferredCursorEvents.delete(e),this.deferredAcpEvents.delete(e),this.deferredPiEvents.delete(e),this.deferredOpenHumanEvents.delete(e),this.deferredCodeWhaleEvents.delete(e),this.deferredOpenCodeEvents.delete(e),this.deferredAgyEvents.delete(e)}getMap(e){switch(e){case"claude":return this.deferredClaudeEvents;case"codex":return this.deferredCodexEvents;case"cursor":return this.deferredCursorEvents;case"acp":return this.deferredAcpEvents;case"pi":return this.deferredPiEvents;case"openhuman":return this.deferredOpenHumanEvents;case"codewhale":return this.deferredCodeWhaleEvents;case"opencode":return this.deferredOpenCodeEvents;case"agy":return this.deferredAgyEvents}}}export{_ as DeferredEventManager};