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.
6 lines (5 loc) • 3.15 kB
JavaScript
import{HookSignalStore as S}from"../core/hooks/hook-signal-store.js";import{resolveRuntimePaths as g}from"../core/config/paths.js";import{resolveLogRotationOptions as y}from"../core/log/rotation.js";import{PermissionStore as v}from"../core/persistence/permission-store.js";import{QuestionStore as k}from"../core/persistence/question-store.js";import{readStdinJSON as A}from"./lib/read-stdin.js";const h=1e3,q=300*1e3;function p(t){const e={hookSpecificOutput:{hookEventName:"PermissionRequest",permissionDecision:t}};process.stdout.write(JSON.stringify(e)+`
`)}function O(t){const e={hookSpecificOutput:{hookEventName:"PermissionRequest",decision:{behavior:"allow",updatedInput:t}}};process.stdout.write(JSON.stringify(e)+`
`)}function _(t){if(t&&typeof t=="object"&&!Array.isArray(t))return t;if(typeof t=="string")try{const e=JSON.parse(t);if(e&&typeof e=="object"&&!Array.isArray(e))return e}catch{return{}}return{}}function R(t,e,o){if(e&&String(e.type??"")==="map"){const d=Array.isArray(e.entries)?e.entries:[],n={};for(const i of d){if(!i||typeof i!="object")continue;const l=i,w=String(l.key??"").trim(),f=String(l.value??"").trim();w&&f&&(n[w]=f)}if(Object.keys(n).length>0)return{...t,answers:n}}const s=(e&&String(e.type??"")==="text"?String(e.value??"").trim():o.trim())||o.trim(),r=Array.isArray(t.questions)?t.questions:[],u={},a=r[0],m=a&&typeof a=="object"?String(a.question??a.header??"question"):"question";return u[m]=s,{...t,answers:u}}async function D(t){const e=g(),o=_(t.tool_input),c=`question-${Date.now()}-${Math.random().toString(36).slice(2,8)}`,s=new k(e.questionRequestsDir),r=Array.isArray(o.questions)?o.questions:[];await s.writeRequest({request_id:c,questions:r,created_at:Date.now(),session_id:String(t.session_id??"").trim(),event_id:String(t.event_id??"").trim()});const u=y(),a=process.env.GRIX_HOOK_SIGNALS_PATH||e.hookSignalsPath;await new S(a,e.hookSignalsLogPath,void 0,u).recordHookEvent(t);const d=Date.now()+q;for(;Date.now()<d;){await new Promise(i=>setTimeout(i,h));const n=await s.getRequest(c);if(n?.resolved){n.resolution==="answer"&&(typeof n.answer=="string"||n.resolution_payload)?O(R(o,n.resolution_payload,String(n.answer??"").trim())):p("deny"),await s.cleanResolved();return}}await s.resolveRequest(c,"cancel"),p("deny")}async function P(){const t=await A(2e3);if(t.hook_event_name!=="PermissionRequest"){process.stdout.write(`{}
`);return}const e=String(t.tool_name??"");if(e==="AskUserQuestion"){await D(t);return}const o=g(),c=_(t.tool_input),s=`perm-${Date.now()}-${Math.random().toString(36).slice(2,8)}`,r=new v(o.permissionRequestsDir);await r.writeRequest({request_id:s,tool_name:e,tool_input:JSON.stringify(c),created_at:Date.now()});const u=y(),a=process.env.GRIX_HOOK_SIGNALS_PATH||o.hookSignalsPath;await new S(a,o.hookSignalsLogPath,void 0,u).recordHookEvent(t);const d=Date.now()+q;for(;Date.now()<d;){await new Promise(l=>setTimeout(l,h));const i=(await r.listPending()).find(l=>l.request_id===s);if(!i||i.resolved){p(i?.resolution==="allow"?"allow":"deny"),await r.cleanResolved();return}}await r.resolveRequest(s,"deny"),p("deny")}P().catch(()=>{p("deny")});