grix-connector 3.7.1 → 3.8.1

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/grix.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import v from"node:path";import{writeFileSync as L}from"node:fs";import{Manager as X}from"./manager.js";import{ensureGrixDirs as K,initLogger as J,log as n,installProcessLogRotation as q,setConsoleOutput as Y}from"./core/log/index.js";import{HealthServer as z,bindPortOrFail as N}from"./core/runtime/index.js";import{writePidFile as Q,removePidFile as P,readDaemonPid as Z}from"./core/runtime/index.js";import{resolveRuntimePaths as T}from"./core/config/index.js";import{supportsDirectProviderConfig as ee}from"./core/config/provider-env.js";import{ServiceManager as te}from"./service/service-manager.js";import{killProcessesByCommandLine as oe,isWindowsElevated as re}from"./service/process-control.js";import{acquireDaemonLock as ne,isLockHolderSameProcess as ae,readDaemonLock as se,releaseDaemonLock as k}from"./runtime/daemon-lock.js";import{writeDaemonStatus as $,removeDaemonStatus as ie}from"./runtime/service-state.js";import{AdminServer as le,generateToken as ce,writeTokenFile as de}from"./core/admin/index.js";import{initSentry as pe,closeSentry as F,reportFatal as O}from"./core/observability/sentry.js";import{initProxyManager as me,getProxyManager as m,relayHostsForClientType as _}from"./core/proxy/index.js";import{stopProxyIfNobodyNeedsIt as ge,disableAllRelayAndRestart as fe,setOneAgentRelayAndRestart as ue}from"./core/proxy/relay-orchestration.js";import{setAgentRelayCredential as he}from"./core/proxy/relay-credential.js";import{resolveClientVersion as ye}from"./core/util/client-version.js";import{parseCliArgs as we}from"./core/util/cli-args.js";const{command:u,flags:g,unknownFlags:C}=we(process.argv.slice(2));if(C.length>0&&(console.error(`Unknown option${C.length>1?"s":""}: ${C.map(t=>`--${t}`).join(", ")}
3
- Run \`grix-connector --help\` to see the supported commands and options.`),process.exit(1)),g.version&&(console.log(ye()),process.exit(0)),g.help&&(console.log(`grix-connector \u2014 Unified AI Agent Bridge
2
+ import b from"node:path";import{writeFileSync as M}from"node:fs";import{Manager as q}from"./manager.js";import{ensureGrixDirs as z,initLogger as Q,log as a,installProcessLogRotation as Z,setConsoleOutput as ee}from"./core/log/index.js";import{HealthServer as te,bindPortOrFail as B}from"./core/runtime/index.js";import{writePidFile as re,removePidFile as I,readDaemonPid as oe}from"./core/runtime/index.js";import{resolveRuntimePaths as U}from"./core/config/index.js";import{supportsDirectProviderConfig as ne}from"./core/config/provider-env.js";import{ServiceManager as ae}from"./service/service-manager.js";import{killProcessesByCommandLine as se,isWindowsElevated as ie}from"./service/process-control.js";import{acquireDaemonLock as le,isLockHolderSameProcess as ce,readDaemonLock as de,releaseDaemonLock as k}from"./runtime/daemon-lock.js";import{writeDaemonStatus as F,removeDaemonStatus as pe}from"./runtime/service-state.js";import{AdminServer as me,generateToken as ge,writeTokenFile as fe}from"./core/admin/index.js";import{initSentry as ue,closeSentry as O,reportFatal as C}from"./core/observability/sentry.js";import{initProxyManager as he,getProxyManager as g,relayHostsForClientType as G}from"./core/proxy/index.js";import{stopProxyIfNobodyNeedsIt as ye,disableAllRelayAndRestart as we,setOneAgentRelayAndRestart as Re}from"./core/proxy/relay-orchestration.js";import{setAgentRelayCredential as xe}from"./core/proxy/relay-credential.js";import{applyHermesProfileRelay as Se,clearHermesProfileRelay as Ae,discoverHermesProfiles as ve}from"./core/proxy/hermes-profile-relay.js";import{disableRelayCredential as Ee,enableRelayCredential as Pe,RelayRouteError as j}from"./core/proxy/relay-credential-router.js";import{resolveClientVersion as De}from"./core/util/client-version.js";import{parseCliArgs as be}from"./core/util/cli-args.js";const{command:h,flags:f,unknownFlags:H}=be(process.argv.slice(2));if(H.length>0&&(console.error(`Unknown option${H.length>1?"s":""}: ${H.map(t=>`--${t}`).join(", ")}
3
+ Run \`grix-connector --help\` to see the supported commands and options.`),process.exit(1)),f.version&&(console.log(De()),process.exit(0)),f.help&&(console.log(`grix-connector \u2014 Unified AI Agent Bridge
4
4
 
5
5
  Usage: grix-connector <command> [options]
6
6
 
@@ -34,8 +34,8 @@ Examples:
34
34
  grix-connector start # Start as system service
35
35
  grix-connector status # Check service status
36
36
  grix-connector restart # Restart the service
37
- `),process.exit(0)),u==="reload"){const t=Z();t||(console.error("reload failed: daemon is not running (no pid file)"),process.exit(1));try{process.kill(t,0)}catch{console.error(`reload failed: daemon process ${t} is not running (stale pid file)`),process.exit(1)}{const p=se(T().daemonLockFile);p&&p.pid===t&&!ae(p)&&(console.error(`reload failed: pid ${t} has been reused by another process (stale pid file)`),process.exit(1))}try{process.kill(t,"SIGHUP"),console.log(JSON.stringify({ok:!0,signaled:t},null,2)),process.exit(0)}catch(p){console.error(`reload failed: ${p instanceof Error?p.message:p}`),process.exit(1)}}const G=["start","stop","restart","status"];if(u&&G.includes(u)){process.platform==="win32"&&["start","stop","restart"].includes(u)&&!re()&&console.warn(`Warning: Not running as administrator. Task Scheduler registration is skipped;
37
+ `),process.exit(0)),h==="reload"){const t=oe();t||(console.error("reload failed: daemon is not running (no pid file)"),process.exit(1));try{process.kill(t,0)}catch{console.error(`reload failed: daemon process ${t} is not running (stale pid file)`),process.exit(1)}{const p=de(U().daemonLockFile);p&&p.pid===t&&!ce(p)&&(console.error(`reload failed: pid ${t} has been reused by another process (stale pid file)`),process.exit(1))}try{process.kill(t,"SIGHUP"),console.log(JSON.stringify({ok:!0,signaled:t},null,2)),process.exit(0)}catch(p){console.error(`reload failed: ${p instanceof Error?p.message:p}`),process.exit(1)}}const K=["start","stop","restart","status"];if(h&&K.includes(h)){process.platform==="win32"&&["start","stop","restart"].includes(h)&&!ie()&&console.warn(`Warning: Not running as administrator. Task Scheduler registration is skipped;
38
38
  using Startup folder auto-start instead. For full Task Scheduler integration,
39
- right-click the terminal and select "Run as administrator".`);const t=T(),p=g["config-dir"]??(g.profile?v.join(t.configDir,g.profile):void 0),h=v.resolve(process.argv[1]||`${t.rootDir}/dist/grix.js`),l=new te({cliPath:h,nodePath:process.execPath});try{let d;switch(u){case"start":(await l.status({rootDir:t.rootDir})).installed?d=await l.start({rootDir:t.rootDir}):d=await l.install({rootDir:t.rootDir,configDir:p});break;case"stop":d=await l.stop({rootDir:t.rootDir});break;case"restart":(await l.status({rootDir:t.rootDir})).installed?d=await l.restart({rootDir:t.rootDir}):d=await l.install({rootDir:t.rootDir,configDir:p});break;case"status":d=await l.status({rootDir:t.rootDir});break}console.log(JSON.stringify(d,null,2)),process.exit(0)}catch(d){console.error(`${u} failed: ${d instanceof Error?d.message:d}`),process.exit(1)}}else u&&(console.error(`Unknown command: ${u}
40
- Valid commands: ${G.join(", ")}`),process.exit(1));const c=T(),Se=g["config-dir"]??(g.profile?`${c.configDir}/${g.profile}`:void 0),a=new X,I=new z,j=ce(),w=new le(j);let U=!1;async function M(t){process.stderr.write(t.message+`
41
- `),n.error("main",t.message.replace(/\n/g," \u2014 ")),await $(c.daemonStatusFile,{state:"failed",pid:process.pid,updated_at:Date.now(),reason:`port_bind_${t.kind}:${t.label}:${t.port}`}).catch(()=>{}),await F(),k(c.daemonLockFile).catch(()=>{}),P(),process.exit(1)}async function b(t){if(U)return;U=!0,n.info("main",`Received ${t}, shutting down...`),I.markShuttingDown();const p=setTimeout(()=>{n.error("main","Shutdown timed out, forcing exit"),k(c.daemonLockFile).catch(()=>{}),P(),process.exit(2)},1e4);try{await a.stop(),await m()?.stop().catch(()=>{}),await w.stop(),await I.stop(),await F(),await k(c.daemonLockFile),await ie(c.daemonStatusFile).catch(()=>{}),clearTimeout(p),P(),n.info("main","Shutdown complete"),process.exit(0)}catch(h){n.error("main",`Shutdown error: ${h}`),k(c.daemonLockFile).catch(()=>{}),P(),process.exit(2)}}async function xe(){K(),J(),await pe(),q(c.stdoutLogFile,c.stderrLogFile),Y(!1),process.platform==="win32"&&await oe("GrixConnectorDaemon",{platform:"win32"});try{await ne(c.daemonLockFile,c.rootDir)}catch(e){console.error(e instanceof Error?e.message:e),process.exit(1)}Q(),n.info("main",`grix-connector starting (PID ${process.pid})`),await $(c.daemonStatusFile,{state:"starting",pid:process.pid,updated_at:Date.now()});const t=parseInt(g["health-port"]??process.env.GRIX_HEALTH_PORT??"19579",10);{const e=await N({label:"health",port:t,envVar:"GRIX_HEALTH_PORT",cliFlag:"health-port",start:i=>I.start(i)});e&&await M(e)}const p=v.join(c.dataDir,"health-port");L(p,String(t),"utf-8"),process.on("SIGINT",()=>b("SIGINT")),process.on("SIGTERM",()=>b("SIGTERM")),process.on("SIGHUP",()=>{U||(n.info("main","Received SIGHUP, reloading config..."),a.reload().then(e=>n.info("main",`reload done: ${JSON.stringify(e)}`)).catch(e=>n.error("main",`reload failed: ${e instanceof Error?e.message:e}`)))});let h="",l=0,d;process.on("uncaughtException",e=>{const i=e instanceof Error?e.stack??e.message:String(e);i===h?(l++,(l<=3||l%100===0)&&n.error("main",`Uncaught exception (x${l}): ${i}`)):(l>3&&n.error("main",`Previous exception repeated ${l} times total`),h=i,l=1,n.error("main",`Uncaught exception: ${e instanceof Error?e.stack:e}`),d||(d=setTimeout(()=>{l>3&&n.error("main",`Previous exception repeated ${l} times total`),h="",l=0,d=void 0},1e4).unref())),!B(e)&&(O(e,"uncaughtException"),b("uncaughtException"))}),process.on("unhandledRejection",e=>{n.error("main",`Unhandled rejection: ${e}`),!B(e)&&(O(e,"unhandledRejection"),b("unhandledRejection"))});const S=me(c.dataDir);await S.clearRuntimeState();const x=S.getRelayAgents();if(x.length>0)try{await S.startIfAnyRelayAgent(),n.info("main",`mitm proxy started for relay agents: ${x.join(", ")} (per-agent; others stay direct)`)}catch(e){n.error("main",`mitm proxy FAILED to start (relay agents: ${x.join(", ")}): ${e}. These agents will REFUSE to start (they must not silently fall back to your own account). Fix the proxy or turn relay off for them. Other agents are unaffected.`)}else n.info("main",'mitm proxy idle (no agent has Grix relay enabled; enable: PUT /api/proxy/agents/<name>/enabled {"enabled":true})');if(I.setStatusProvider(()=>a.getAgentsStatus()),await a.start(Se),x.length>0){const e=a.getAgentsStatus();for(const i of x){const o=e.find(s=>s.name===i);if(!o)continue;const r=_(o.clientType);r.length!==0&&await S.setAgentRelayEnabled(i,!0,{relayHosts:r}).catch(s=>{n.warn("main",`failed to reconcile relay hosts for "${i}": ${s}`)})}}const H=parseInt(g["admin-port"]??process.env.GRIX_ADMIN_PORT??"19580",10);if(w.setAgentHandler({list:()=>a.getAgentsStatus(),add:e=>a.addAgent(e),remove:e=>a.removeAgent(e),restart:e=>a.restartAgent(e),reload:()=>a.reload()}),w.setUpgradeHandler({check:()=>a.checkUpgrade(),trigger:()=>a.triggerUpgrade()}),w.setProbeHandler({probeAll:e=>a.probeAll(e),probeOne:(e,i)=>a.probeOne(e,i)}),w.setInstallHandler({listInstallable:()=>a.listInstallable(),installAgent:e=>a.installAgent(e),getInstallProgress:e=>a.getInstallProgress(e)}),m()){const e=async()=>{const o=m();o&&await ge(o,a)&&n.info("main","no agent uses Grix relay anymore; mitm proxy stopped")};a.setRelayEnvSettledHandler(()=>{e().catch(o=>{n.warn("main",`failed to stop idle mitm proxy: ${o}`)})});const i=()=>{const o=m(),r=o.getRelayAgents(),s=o.getDegradedRelayAgents();return{enabled:r.length>0,relayAgents:r,staleRelayAgents:a.getAgentsWithStaleRelayEnv(),degradedRelayAgents:s,runtime:o.getRuntimeInfo(),config:o.getConfigSnapshot()}};w.setProxyHandler({status:()=>i(),setAgentRelay:async(o,r)=>{const s=m(),y=a.getAgentsStatus().find(D=>D.name===o);if(y&&ee(y.clientType))return r?n.info("main",`relay enable for native provider agent "${o}" is a no-op; use relay-credential to enable`):await a.setAgentProvider(o,void 0),{...i(),restarted:!r,busy:!1};let A;if(r){if(!y)throw Object.assign(new Error(`Agent "${o}" not found`),{code:"NOT_FOUND"});if(A=_(y.clientType),A.length===0)throw Object.assign(new Error(`client type "${y.clientType??""}" does not support Grix relay`),{code:"UNSUPPORTED_CLIENT_TYPE"})}const{restarted:f,busy:E}=await ue(s,a,{info:D=>n.info("main",D),warn:D=>n.warn("main",D)},{agentName:o,enabled:r,relayHosts:A});return{...i(),restarted:f,busy:E}},setAgentRelayCredential:async(o,r)=>{const s=m(),R=a.getAgentsStatus(),{restarted:y,busy:A}=await he(s,a,f=>R.find(E=>E.name===f),{info:f=>n.info("main",f),warn:f=>n.warn("main",f)},{localName:o,agentId:r.agentId,virtualKey:r.virtualKey,anthropicBaseUrl:r.anthropicBaseUrl,openaiBaseUrl:r.openaiBaseUrl,model:r.model},(f,E)=>a.setAgentProvider(f,E));return{...i(),restarted:y,busy:A}},disableAll:async()=>{const o=m();await fe(o,a,{info:s=>n.info("main",s),warn:s=>n.warn("main",s)});const r=await a.clearDirectProviderConfigs();return r.length>0&&n.info("main",`relay disable-all cleared native provider config for: ${r.join(", ")}`),i()},setRoute:async(o,r)=>{const s=r,R=m();return R.setRoute({routeKey:o,targetBaseUrl:s.targetBaseUrl,...s.headers?{headers:s.headers}:{},...s.model?{model:s.model}:{},...s.modelMap?{modelMap:s.modelMap}:{},...s.passthrough?{passthrough:!0}:{},...s.relayOnly?{relayOnly:!0}:{},...s.codexResponsesToChat?{codexResponsesToChat:!0}:{}}),await R.persistConfig(),i()},deleteRoute:async o=>{const r=m();r.deleteRoute(o),await r.persistConfig()},setDefaultRoute:async o=>{const r=m();return r.setDefaultRouteKey(o),await r.persistConfig(),i()},setInterceptHosts:async o=>{const r=m();return r.setInterceptHosts(o),await r.persistConfig(),i()}})}{const e=await N({label:"admin",port:H,envVar:"GRIX_ADMIN_PORT",cliFlag:"admin-port",start:i=>w.start(i)});e&&await M(e)}const W=v.join(c.dataDir,"admin-token"),V=v.join(c.dataDir,"admin-port");de(W,j),L(V,String(H),"utf-8"),await $(c.daemonStatusFile,{state:"running",pid:process.pid,updated_at:Date.now()}),process.send&&process.send("ready"),n.info("main","grix-connector ready")}xe().catch(async t=>{n.error("main",`Fatal: ${t}`),O(t,"startup"),await F(),k(c.daemonLockFile).catch(()=>{}),P(),process.exit(1)});const Re=new Set(["ECONNRESET","ECONNREFUSED","ETIMEDOUT","EPIPE","EAI_AGAIN","ENOTFOUND","EHOSTUNREACH","ENETUNREACH","EIO"]);function B(t){return t instanceof Error&&"code"in t?Re.has(t.code):!1}
39
+ right-click the terminal and select "Run as administrator".`);const t=U(),p=f["config-dir"]??(f.profile?b.join(t.configDir,f.profile):void 0),w=b.resolve(process.argv[1]||`${t.rootDir}/dist/grix.js`),l=new ae({cliPath:w,nodePath:process.execPath});try{let d;switch(h){case"start":(await l.status({rootDir:t.rootDir})).installed?d=await l.start({rootDir:t.rootDir}):d=await l.install({rootDir:t.rootDir,configDir:p});break;case"stop":d=await l.stop({rootDir:t.rootDir});break;case"restart":(await l.status({rootDir:t.rootDir})).installed?d=await l.restart({rootDir:t.rootDir}):d=await l.install({rootDir:t.rootDir,configDir:p});break;case"status":d=await l.status({rootDir:t.rootDir});break}console.log(JSON.stringify(d,null,2)),process.exit(0)}catch(d){console.error(`${h} failed: ${d instanceof Error?d.message:d}`),process.exit(1)}}else h&&(console.error(`Unknown command: ${h}
40
+ Valid commands: ${K.join(", ")}`),process.exit(1));const c=U(),Ie=f["config-dir"]??(f.profile?`${c.configDir}/${f.profile}`:void 0),s=new q,T=new te,V=ge(),y=new me(V);let L=!1;async function X(t){process.stderr.write(t.message+`
41
+ `),a.error("main",t.message.replace(/\n/g," \u2014 ")),await F(c.daemonStatusFile,{state:"failed",pid:process.pid,updated_at:Date.now(),reason:`port_bind_${t.kind}:${t.label}:${t.port}`}).catch(()=>{}),await O(),k(c.daemonLockFile).catch(()=>{}),I(),process.exit(1)}async function $(t){if(L)return;L=!0,a.info("main",`Received ${t}, shutting down...`),T.markShuttingDown();const p=setTimeout(()=>{a.error("main","Shutdown timed out, forcing exit"),k(c.daemonLockFile).catch(()=>{}),I(),process.exit(2)},1e4);try{await s.stop(),await g()?.stop().catch(()=>{}),await y.stop(),await T.stop(),await O(),await k(c.daemonLockFile),await pe(c.daemonStatusFile).catch(()=>{}),clearTimeout(p),I(),a.info("main","Shutdown complete"),process.exit(0)}catch(w){a.error("main",`Shutdown error: ${w}`),k(c.daemonLockFile).catch(()=>{}),I(),process.exit(2)}}async function ke(){z(),Q(),await ue(),Z(c.stdoutLogFile,c.stderrLogFile),ee(!1),process.platform==="win32"&&await se("GrixConnectorDaemon",{platform:"win32"});try{await le(c.daemonLockFile,c.rootDir)}catch(e){console.error(e instanceof Error?e.message:e),process.exit(1)}re(),a.info("main",`grix-connector starting (PID ${process.pid})`),await F(c.daemonStatusFile,{state:"starting",pid:process.pid,updated_at:Date.now()});const t=parseInt(f["health-port"]??process.env.GRIX_HEALTH_PORT??"19579",10);{const e=await B({label:"health",port:t,envVar:"GRIX_HEALTH_PORT",cliFlag:"health-port",start:r=>T.start(r)});e&&await X(e)}const p=b.join(c.dataDir,"health-port");M(p,String(t),"utf-8"),process.on("SIGINT",()=>$("SIGINT")),process.on("SIGTERM",()=>$("SIGTERM")),process.on("SIGHUP",()=>{L||(a.info("main","Received SIGHUP, reloading config..."),s.reload().then(e=>a.info("main",`reload done: ${JSON.stringify(e)}`)).catch(e=>a.error("main",`reload failed: ${e instanceof Error?e.message:e}`)))});let w="",l=0,d;process.on("uncaughtException",e=>{const r=e instanceof Error?e.stack??e.message:String(e);r===w?(l++,(l<=3||l%100===0)&&a.error("main",`Uncaught exception (x${l}): ${r}`)):(l>3&&a.error("main",`Previous exception repeated ${l} times total`),w=r,l=1,a.error("main",`Uncaught exception: ${e instanceof Error?e.stack:e}`),d||(d=setTimeout(()=>{l>3&&a.error("main",`Previous exception repeated ${l} times total`),w="",l=0,d=void 0},1e4).unref())),!W(e)&&(C(e,"uncaughtException"),$("uncaughtException"))}),process.on("unhandledRejection",e=>{a.error("main",`Unhandled rejection: ${e}`),!W(e)&&(C(e,"unhandledRejection"),$("unhandledRejection"))});const x=he(c.dataDir);await x.clearRuntimeState();const S=x.getRelayAgents();if(S.length>0)try{await x.startIfAnyRelayAgent(),a.info("main",`mitm proxy started for relay agents: ${S.join(", ")} (per-agent; others stay direct)`)}catch(e){a.error("main",`mitm proxy FAILED to start (relay agents: ${S.join(", ")}): ${e}. These agents will REFUSE to start (they must not silently fall back to your own account). Fix the proxy or turn relay off for them. Other agents are unaffected.`)}else a.info("main",'mitm proxy idle (no agent has Grix relay enabled; enable: PUT /api/proxy/agents/<name>/enabled {"enabled":true})');if(T.setStatusProvider(()=>s.getAgentsStatus()),await s.start(Ie),S.length>0){const e=s.getAgentsStatus();for(const r of S){const m=e.find(n=>n.name===r);if(!m)continue;const o=G(m.clientType);o.length!==0&&await x.setAgentRelayEnabled(r,!0,{relayHosts:o}).catch(n=>{a.warn("main",`failed to reconcile relay hosts for "${r}": ${n}`)})}}const _=parseInt(f["admin-port"]??process.env.GRIX_ADMIN_PORT??"19580",10);y.setAgentHandler({list:()=>s.getAgentsStatus(),add:e=>s.addAgent(e),remove:e=>s.removeAgent(e),restart:e=>s.restartAgent(e),reload:()=>s.reload()}),y.setUpgradeHandler({check:()=>s.checkUpgrade(),trigger:()=>s.triggerUpgrade()}),y.setProbeHandler({probeAll:e=>s.probeAll(e),probeOne:(e,r)=>s.probeOne(e,r)}),y.setInstallHandler({listInstallable:()=>s.listInstallable(),installAgent:e=>s.installAgent(e),getInstallProgress:e=>s.getInstallProgress(e)});let A=null;if(g()){const e=async()=>{const o=g();o&&await ye(o,s)&&a.info("main","no agent uses Grix relay anymore; mitm proxy stopped")};s.setRelayEnvSettledHandler(()=>{e().catch(o=>{a.warn("main",`failed to stop idle mitm proxy: ${o}`)})});const r=()=>{const o=g(),n=o.getRelayAgents(),i=o.getDegradedRelayAgents();return{enabled:n.length>0,relayAgents:n,staleRelayAgents:s.getAgentsWithStaleRelayEnv(),degradedRelayAgents:i,runtime:o.getRuntimeInfo(),config:o.getConfigSnapshot()}},m={status:()=>r(),setAgentRelay:async(o,n)=>{const i=g(),R=s.getAgentsStatus().find(D=>D.name===o);if(R&&ne(R.clientType))return n?a.info("main",`relay enable for native provider agent "${o}" is a no-op; use relay-credential to enable`):await s.setAgentProvider(o,void 0),{...r(),restarted:!n,busy:!1};let E;if(n){if(!R)throw Object.assign(new Error(`Agent "${o}" not found`),{code:"NOT_FOUND"});if(E=G(R.clientType),E.length===0)throw Object.assign(new Error(`client type "${R.clientType??""}" does not support Grix relay`),{code:"UNSUPPORTED_CLIENT_TYPE"})}const{restarted:u,busy:P}=await Re(i,s,{info:D=>a.info("main",D),warn:D=>a.warn("main",D)},{agentName:o,enabled:n,relayHosts:E});return{...r(),restarted:u,busy:P}},setAgentRelayCredential:async(o,n)=>{const i=g(),v=s.getAgentsStatus(),{restarted:R,busy:E}=await xe(i,s,u=>v.find(P=>P.name===u),{info:u=>a.info("main",u),warn:u=>a.warn("main",u)},{localName:o,agentId:n.agentId,virtualKey:n.virtualKey,anthropicBaseUrl:n.anthropicBaseUrl,openaiBaseUrl:n.openaiBaseUrl,model:n.model},(u,P)=>s.setAgentProvider(u,P));return{...r(),restarted:R,busy:E}},disableAll:async()=>{const o=g();await we(o,s,{info:i=>a.info("main",i),warn:i=>a.warn("main",i)});const n=await s.clearDirectProviderConfigs();return n.length>0&&a.info("main",`relay disable-all cleared native provider config for: ${n.join(", ")}`),r()},setRoute:async(o,n)=>{const i=n,v=g();return v.setRoute({routeKey:o,targetBaseUrl:i.targetBaseUrl,...i.headers?{headers:i.headers}:{},...i.model?{model:i.model}:{},...i.modelMap?{modelMap:i.modelMap}:{},...i.passthrough?{passthrough:!0}:{},...i.relayOnly?{relayOnly:!0}:{},...i.codexResponsesToChat?{codexResponsesToChat:!0}:{}}),await v.persistConfig(),r()},deleteRoute:async o=>{const n=g();n.deleteRoute(o),await n.persistConfig()},setDefaultRoute:async o=>{const n=g();return n.setDefaultRouteKey(o),await n.persistConfig(),r()},setInterceptHosts:async o=>{const n=g();return n.setInterceptHosts(o),await n.persistConfig(),r()}};A=m,y.setProxyHandler(m)}const N={listAgents:()=>s.getAgentsStatus(),enableManaged:(e,r,m)=>{if(!A)throw new j(`agent "${e}" needs the MITM proxy for relay, but it is not running`,"PROXY_UNAVAILABLE");return A.setAgentRelayCredential(e,{agentId:r,virtualKey:m.virtualKey,anthropicBaseUrl:m.anthropicBaseUrl,openaiBaseUrl:m.openaiBaseUrl,model:m.model})},disableManaged:e=>{if(!A)throw new j(`agent "${e}" needs the MITM proxy for relay, but it is not running`,"PROXY_UNAVAILABLE");return A.setAgentRelay(e,!1)},enableHermesProfile:(e,r)=>Se({agentId:e,baseUrl:r.openaiBaseUrl??"",virtualKey:r.virtualKey,model:r.model??""}),disableHermesProfile:e=>Ae(e)};y.setRelayCredentialHandler({listHermesProfiles:()=>ve(),enable:async(e,r)=>{const{target:m,result:o}=await Pe(N,e,r);return{target:m,...o}},disable:async e=>{const{target:r,result:m}=await Ee(N,e);return{target:r,...m}}});{const e=await B({label:"admin",port:_,envVar:"GRIX_ADMIN_PORT",cliFlag:"admin-port",start:r=>y.start(r)});e&&await X(e)}const J=b.join(c.dataDir,"admin-token"),Y=b.join(c.dataDir,"admin-port");fe(J,V),M(Y,String(_),"utf-8"),await F(c.daemonStatusFile,{state:"running",pid:process.pid,updated_at:Date.now()}),process.send&&process.send("ready"),a.info("main","grix-connector ready")}ke().catch(async t=>{a.error("main",`Fatal: ${t}`),C(t,"startup"),await O(),k(c.daemonLockFile).catch(()=>{}),I(),process.exit(1)});const Te=new Set(["ECONNRESET","ECONNREFUSED","ETIMEDOUT","EPIPE","EAI_AGAIN","ENOTFOUND","EHOSTUNREACH","ENETUNREACH","EIO"]);function W(t){return t instanceof Error&&"code"in t?Te.has(t.code):!1}
@@ -1 +1 @@
1
- function a(t){const o=new Set([`http://127.0.0.1:${t.serverPort}`,`http://localhost:${t.serverPort}`,...t.allowedOrigins]),e=new Set([`127.0.0.1:${t.serverPort}`,`localhost:${t.serverPort}`,...t.allowedHosts]);return{validateRequest(s){const r=i(s,o);if(!r.ok)return r;const n=l(s,e);return n.ok?{ok:!0}:n}}}function i(t,o){const e=t.headers.origin;return e?o.has(e)?{ok:!0}:{ok:!1,statusCode:403,message:`Origin not allowed: ${e}`}:{ok:!0}}function l(t,o){const e=t.headers.host;return e?o.has(e)?{ok:!0}:{ok:!1,statusCode:403,message:`Host not allowed: ${e}`}:{ok:!1,statusCode:403,message:"Missing Host header"}}export{a as createSecurityPolicy};
1
+ function a(o){const e=new Set([`http://127.0.0.1:${o.serverPort}`,`http://localhost:${o.serverPort}`,...o.allowedOrigins]),t=new Set([`127.0.0.1:${o.serverPort}`,`localhost:${o.serverPort}`,...o.allowedHosts]);return{validateRequest(s){const r=i(s,e);if(!r.ok)return r;const n=l(s,t);return n.ok?{ok:!0}:n}}}function i(o,e){const t=o.headers.origin;return t?e.has(t)?{ok:!0}:{ok:!1,statusCode:403,message:`Origin not allowed: ${t}`}:{ok:!0}}function l(o,e){const t=o.headers.host;return t?e.has(t)?{ok:!0}:{ok:!1,statusCode:403,message:`Host not allowed: ${t}`}:{ok:!1,statusCode:403,message:"Missing Host header"}}export{a as createSecurityPolicy};