grix-connector 4.11.11 → 4.11.13
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/claude/claude-bridge-server.js +1 -1
- package/dist/adapter/claude/claude-tools.js +1 -1
- package/dist/adapter/claude/claude-worker-client.js +1 -1
- package/dist/adapter/claude/mcp-http-launcher.js +2 -2
- package/dist/adapter/claude/result-timeout.js +1 -1
- package/dist/adapter/codex/codex-bridge.js +8 -8
- package/dist/assets/dsh-bridge/grix-dsh-bridge-4.11.13.tgz +0 -0
- package/dist/assets/dsh-bridge/manifest.json +5 -5
- package/dist/core/access/allowlist-store.js +1 -1
- package/dist/core/file-ops/list-files.js +1 -1
- package/dist/grix.js +8 -8
- package/dist/log.js +2 -2
- package/dist/mcp/stream-http/config.js +1 -1
- package/dist/mcp/stream-http/connection-binding.js +1 -1
- package/dist/mcp/stream-http/tool-executor.js +1 -1
- package/dist/mcp/stream-http/tool-registry.js +1 -1
- package/dist/mcp/stream-http/tool-schemas.js +1 -1
- package/dist/runtime/duplicate-daemon.js +2 -2
- package/dist/runtime/startup-phases.js +1 -0
- package/dist/service/platform-adapter.js +18 -18
- package/dist/service/service-manager.js +2 -3
- package/package.json +1 -1
- package/dist/assets/dsh-bridge/grix-dsh-bridge-4.11.11.tgz +0 -0
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
|
-
"bridgeVersion": "4.11.
|
|
4
|
-
"tarball": "grix-dsh-bridge-4.11.
|
|
5
|
-
"size":
|
|
3
|
+
"bridgeVersion": "4.11.13",
|
|
4
|
+
"tarball": "grix-dsh-bridge-4.11.13.tgz",
|
|
5
|
+
"size": 23420,
|
|
6
6
|
"unpackedSize": 94155,
|
|
7
|
-
"shasum": "
|
|
8
|
-
"integrity": "sha512-
|
|
7
|
+
"shasum": "de5d0f4e5025e7e12a543763b84aae33215f90f6",
|
|
8
|
+
"integrity": "sha512-a4c5ZtzjXHn65NcKRm5fJcIrPMU+j25424dXxkH0mhqy+U/WMIHtdhm8/ekaqaVTKY3bc7QXW323Yjo/FxymqQ=="
|
|
9
9
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{readJSONFile as o,writeJSONFileAtomic as
|
|
1
|
+
import{readJSONFile as o,writeJSONFileAtomic as e}from"../util/json-file.js";function n(t){const r=o(t);return r&&typeof r=="object"&&"owners"in r&&Array.isArray(r.owners)?r.owners.filter(i=>typeof i=="string"&&i.trim().length>0):[]}async function s(t,r){await e(t,{owners:r})}export{n as readAllowlist,s as writeAllowlist};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{readdir as r,stat as m}from"node:fs/promises";import{join as l,extname as d}from"node:path";const x={pdf:"application/pdf",doc:"application/msword",docx:"application/vnd.openxmlformats-officedocument.wordprocessingml.document",xls:"application/vnd.ms-excel",xlsx:"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",ppt:"application/vnd.ms-powerpoint",pptx:"application/vnd.openxmlformats-officedocument.presentationml.presentation",txt:"text/plain",md:"text/markdown",csv:"text/csv",json:"application/json",xml:"application/xml",yaml:"text/yaml",yml:"text/yaml",html:"text/html",css:"text/css",js:"text/javascript",ts:"text/typescript",zip:"application/zip",rar:"application/x-rar-compressed","7z":"application/x-7z-compressed",tar:"application/x-tar",gz:"application/gzip",jpg:"image/jpeg",jpeg:"image/jpeg",png:"image/png",gif:"image/gif",webp:"image/webp",svg:"image/svg+xml",mp4:"video/mp4",mov:"video/quicktime",avi:"video/x-msvideo",mkv:"video/x-matroska",webm:"video/webm",mp3:"audio/mpeg",wav:"audio/wav",flac:"audio/flac",aac:"audio/aac"};function n(a){const p=d(a).slice(1).toLowerCase();return x[p]}async function f(a,p=!1){const c=await r(a,{withFileTypes:!0}),s=[];for(const
|
|
1
|
+
import{readdir as r,stat as m}from"node:fs/promises";import{join as l,extname as d}from"node:path";const x={pdf:"application/pdf",doc:"application/msword",docx:"application/vnd.openxmlformats-officedocument.wordprocessingml.document",xls:"application/vnd.ms-excel",xlsx:"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",ppt:"application/vnd.ms-powerpoint",pptx:"application/vnd.openxmlformats-officedocument.presentationml.presentation",txt:"text/plain",md:"text/markdown",csv:"text/csv",json:"application/json",xml:"application/xml",yaml:"text/yaml",yml:"text/yaml",html:"text/html",css:"text/css",js:"text/javascript",ts:"text/typescript",zip:"application/zip",rar:"application/x-rar-compressed","7z":"application/x-7z-compressed",tar:"application/x-tar",gz:"application/gzip",jpg:"image/jpeg",jpeg:"image/jpeg",png:"image/png",gif:"image/gif",webp:"image/webp",svg:"image/svg+xml",mp4:"video/mp4",mov:"video/quicktime",avi:"video/x-msvideo",mkv:"video/x-matroska",webm:"video/webm",mp3:"audio/mpeg",wav:"audio/wav",flac:"audio/flac",aac:"audio/aac"};function n(a){const p=d(a).slice(1).toLowerCase();return x[p]}async function f(a,p=!1){const c=await r(a,{withFileTypes:!0}),s=[];for(const t of c){if(!p&&t.name.startsWith("."))continue;const i=l(a,t.name),e={id:i,name:t.name,is_directory:t.isDirectory()};try{if(t.isDirectory()){const o=await m(i);e.modified_at=o.mtime.toISOString()}else{const o=await m(i);e.size=o.size,e.modified_at=o.mtime.toISOString(),e.mime_type=n(t.name)}}catch{}s.push(e)}return s.sort((t,i)=>t.is_directory!==i.is_directory?t.is_directory?-1:1:t.name.localeCompare(i.name)),s}export{f as listFiles,n as resolveMimeType};
|
package/dist/grix.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import b from"node:path";import{writeFileSync as
|
|
3
|
-
Run \`grix-connector --help\` to see the supported commands and options.`),process.exit(1)),
|
|
2
|
+
import b from"node:path";import{writeFileSync as ie}from"node:fs";import{Manager as Te}from"./manager.js";import{ensureGrixDirs as $e,initLogger as Le,getLoggerStatus as Ue,log as i,installProcessLogRotation as He,setConsoleOutput as se}from"./core/log/index.js";import{HealthServer as Oe,bindPortOrFail as ce}from"./core/runtime/index.js";import{writePidFile as Fe,removePidFile as T,readDaemonPid as le}from"./core/runtime/index.js";import{killOrphanedClaudeProcesses as Ne}from"./core/runtime/index.js";import{resolveRuntimePaths as Y}from"./core/config/index.js";import{supportsNonMitmRelayConfig as Ge}from"./core/config/provider-env.js";import{ServiceManager as de}from"./service/service-manager.js";import{RESTART_EXIT_CODE as Me,UNHEALTHY_EXIT_CODE as Be,markManagedStop as pe,resolveLauncherStore as q,writeCrashNote as je}from"./core/upgrade/version-store.js";import{migrateWindowsWrapper as J}from"./service/windows-wrapper-migration.js";const We=300*1e3;import{killProcessesByCommandLine as Ke,isWindowsElevated as Xe,shouldSweepWindowsWrappers as Ve,getProcessCommandLine as Ye}from"./service/process-control.js";import{buildServiceID as qe}from"./service/service-paths.js";import{isInsideManagedDaemonTree as Je}from"./service/platform-adapter.js";import{acquireDaemonLock as ze,createHealthzHolderProbe as Qe,DaemonAlreadyServingError as Ze,findLiveLockHolder as et,isLockHolderSameProcess as tt,readDaemonLock as z,releaseDaemonLock as N}from"./runtime/daemon-lock.js";import{writeDaemonStatus as B,removeDaemonStatus as rt}from"./runtime/service-state.js";import{readRecentDuplicateDaemonRecord as nt,recordDuplicateDaemon as ot}from"./runtime/duplicate-daemon.js";import{createStartupPhaseTimer as at}from"./runtime/startup-phases.js";import{RemoteAdminSettingsStore as it}from"./core/config/remote-admin-settings.js";import{AdminServer as st,generateToken as ct,writeTokenFile as lt}from"./core/admin/index.js";import{initSentry as dt,closeSentry as j,reportFatal as Q,isWindowsWmicProbeError as pt}from"./core/observability/sentry.js";import{initProxyManager as gt,getProxyManager as h,relayHostsForClientType as ge,RelayStateStore as mt,SecretStore as ut}from"./core/proxy/index.js";import{stopProxyIfNobodyNeedsIt as me,switchAgentRelayMode as Z,reconcileRelayStates as ue}from"./core/proxy/relay-orchestration.js";import{setAgentRelayCredential as fe,RelayCredentialError as he}from"./core/proxy/relay-credential.js";import{RelayFetchError as ye,RelayToggleCoordinator as ft}from"./core/proxy/relay-credential-fetch.js";import{applyHermesProfileRelay as ht,clearHermesProfileRelay as yt,discoverHermesProfiles as wt}from"./core/proxy/hermes-profile-relay.js";import{disableRelayCredential as St,enableRelayCredential as Rt,RelayRouteError as we}from"./core/proxy/relay-credential-router.js";import{upgradeStatusSnapshot as Et}from"./core/upgrade/npm-upgrader.js";import{resolveClientVersion as Dt}from"./core/util/client-version.js";import{parseCliArgs as At}from"./core/util/cli-args.js";const{command:I,flags:E,unknownFlags:ee}=At(process.argv.slice(2));if(ee.length>0&&(console.error(`Unknown option${ee.length>1?"s":""}: ${ee.map(t=>`--${t}`).join(", ")}
|
|
3
|
+
Run \`grix-connector --help\` to see the supported commands and options.`),process.exit(1)),E.version&&(console.log(Dt()),process.exit(0)),E.help&&(console.log(`grix-connector \u2014 Unified AI Agent Bridge
|
|
4
4
|
|
|
5
5
|
Usage: grix-connector <command> [options]
|
|
6
6
|
|
|
@@ -34,10 +34,10 @@ 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)),I==="reload"){const t=
|
|
37
|
+
`),process.exit(0)),I==="reload"){const t=le();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 s=z(Y().daemonLockFile);s&&s.pid===t&&!tt(s)&&(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(s){console.error(`reload failed: ${s instanceof Error?s.message:s}`),process.exit(1)}}const Se="detected connector-managed session; restart delegated to launchd, this process may be terminated by the restart",Re=["start","stop","restart","status"];if(I&&Re.includes(I)){process.platform==="win32"&&["start","stop","restart"].includes(I)&&!Xe()&&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=
|
|
40
|
-
Valid commands: ${
|
|
41
|
-
`),i.warn("main",s);const g=
|
|
42
|
-
`),i.error("main",t.message.replace(/\n/g," \u2014 ")),W("port_bind",t.message);const s=J(c.daemonLockFile);s?.pid===process.pid&&s.instance_id===$&&await G(c.daemonStatusFile,{state:"failed",pid:process.pid,instance_id:$,updated_at:Date.now(),reason:`port_bind_${t.kind}:${t.label}:${t.port}`}).catch(()=>{}),await B(),F(c.daemonLockFile).catch(()=>{}),T(),process.exit(1)}async function _(t){if(j)return;j=!0,i.info("main",`Received ${t}, shutting down...`),M.markShuttingDown();const s=Y();s&&de(s);const g=t==="upgrade-switch"?Ne:t==="launcher-unhealthy"?Ge:null,u=g??2,l=t==="uncaughtException"||t==="unhandledRejection",h=setTimeout(()=>{i.error("main","Shutdown timed out, forcing exit"),F(c.daemonLockFile).catch(()=>{}),T(),process.exit(u)},1e4);try{await o.stop(),await f()?.stop().catch(()=>{}),await x.stop(),await M.stop(),await B(),await F(c.daemonLockFile),await tt(c.daemonStatusFile).catch(()=>{}),clearTimeout(h),T(),i.info("main","Shutdown complete"),process.exit(g??(l?2:0))}catch(S){i.error("main",`Shutdown error: ${S}`),F(c.daemonLockFile).catch(()=>{}),T(),process.exit(u)}}async function bt(){Te(),$e(),Ue(c.stdoutLogFile,c.stderrLogFile),ie(!1);try{$=(await Je(c.daemonLockFile,c.rootDir,2,{isHolderServing:ze(c.dataDir)})).instance_id}catch(e){e instanceof Qe&&At(e.holder),console.error(e instanceof Error?e.message:e),process.exit(1)}if(Xe()){const e=Ye(c.rootDir,"win32");await We(e,{platform:"win32"})}await ct(),Oe(),i.info("main",`grix-connector starting (PID ${process.pid})`);try{Fe({info:e=>i.info("main",e),warn:e=>i.warn("main",e)})}catch(e){i.warn("main",`orphan Claude cleanup failed: ${e instanceof Error?e.message:String(e)}`)}if(await G(c.daemonStatusFile,{state:"starting",pid:process.pid,instance_id:$,updated_at:Date.now()}),process.env.GRIX_LAUNCHER_MANAGED!=="1"&&await new le({cliPath:b.resolve(process.argv[1]??""),nodePath:process.execPath}).adoptLauncher(c.rootDir).then(e=>{e&&i.info("main","Service definition now points at the version-store launcher")}).catch(e=>{i.warn("main",`Launcher adoption failed: ${e instanceof Error?e.message:e}`)}),(await q({rootDir:c.rootDir,requestGracefulShutdown:()=>{_("wrapper-migration")}}).catch(e=>(i.warn("main",`Windows wrapper migration failed: ${e instanceof Error?e.message:e}`),null)))?.handoffStarted)return;process.platform==="win32"&&process.env.GRIX_LAUNCHER_MANAGED!=="1"&&setInterval(()=>{j||q({rootDir:c.rootDir,requestGracefulShutdown:()=>{_("wrapper-migration")}}).then(n=>{n.handoffStarted&&i.info("main","Wrapper handoff started by the periodic migration retry")}).catch(n=>{i.warn("main",`Periodic wrapper migration failed: ${n instanceof Error?n.message:n}`)})},je).unref();const s=parseInt(D["health-port"]??process.env.GRIX_HEALTH_PORT??"19579",10);{const e=await se({label:"health",port:s,envVar:"GRIX_HEALTH_PORT",cliFlag:"health-port",start:n=>M.start(n)});e&&await De(e)}const g=b.join(c.dataDir,"health-port");ae(g,String(s),"utf-8"),process.on("SIGINT",()=>_("SIGINT")),process.on("SIGTERM",()=>_("SIGTERM")),process.on("SIGHUP",()=>{j||(i.info("main","Received SIGHUP, reloading config..."),o.reload().then(e=>i.info("main",`reload done: ${JSON.stringify(e)}`)).catch(e=>i.error("main",`reload failed: ${e instanceof Error?e.message:e}`)))});let u="",l=0,h;process.on("uncaughtException",e=>{const n=e instanceof Error?e.stack??e.message:String(e);n===u?(l++,(l<=3||l%100===0)&&i.error("main",`Uncaught exception (x${l}): ${n}`)):(l>3&&i.error("main",`Previous exception repeated ${l} times total`),u=n,l=1,i.error("main",`Uncaught exception: ${e instanceof Error?e.stack:e}`),h||(h=setTimeout(()=>{l>3&&i.error("main",`Previous exception repeated ${l} times total`),u="",l=0,h=void 0},1e4).unref())),!Ae(e)&&(z(e,"uncaughtException"),W("uncaughtException",e),_("uncaughtException"))}),process.on("unhandledRejection",e=>{i.error("main",`Unhandled rejection: ${e}`),!Ae(e)&&(z(e,"unhandledRejection"),W("unhandledRejection",e),_("unhandledRejection"))});const S=dt(c.dataDir);await S.clearRuntimeState();const k=new pt(b.join(c.dataDir,"proxy","relay-state.json"),{warn:e=>i.warn("main",e)}),N=new gt(b.join(c.dataDir,"secrets"));o.setRelaySecretResolver(e=>N.get(e));const L={hasDirectConfig:e=>o.hasDirectRelayConfig(e),clearDirectConfig:(e,n)=>o.setAgentProvider(e,void 0,{deferRestart:n?.deferRestart===!0})},K=()=>({pm:f(),agents:o,direct:L,store:k,secrets:N}),U=S.getRelayAgents();if(U.length>0)try{await S.startIfAnyRelayAgent(),i.info("main",`mitm proxy started for relay agents: ${U.join(", ")} (per-agent; others stay direct)`)}catch(e){i.error("main",`mitm proxy FAILED to start (relay agents: ${U.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 i.info("main",'mitm proxy idle (no agent has Grix relay enabled; enable: PUT /api/proxy/agents/<name>/enabled {"enabled":true})');let H=null;if(f()){const e=async()=>{const r=f();r&&await ge(r,o)&&i.info("main","no agent uses Grix relay anymore; mitm proxy stopped")};o.setRelayEnvSettledHandler(()=>{const r=f();r&&me(r,L,k),e().catch(a=>{i.warn("main",`failed to stop idle mitm proxy: ${a}`)})});const n=()=>{const r=f(),a=r.getRelayAgents(),p=r.getDegradedRelayAgents();return{enabled:a.length>0,relayAgents:a,staleRelayAgents:o.getAgentsWithStaleRelayEnv(),degradedRelayAgents:p,relayState:k.list(),runtime:r.getRuntimeInfo(),config:r.getConfigSnapshot()}},d=new mt,A={status:()=>n(),setAgentRelay:async(r,a,p)=>{const m=f(),E={info:w=>i.info("main",w),warn:w=>i.warn("main",w)},R=w=>o.getAgentsStatus().find(v=>v.name===w),y=R(r);if(!a){d.cancel(r);const w=await d.runExclusive(r,async()=>{const v=await Q(K(),E,{agentName:r,target:"off"});return{...n(),restarted:v.restarted,busy:v.busy,...v.pending?{pending:v.pending}:{}}});return o.reportRelayStateLocalChange(r),w}if(!y)throw Object.assign(new Error(`Agent "${r}" not found`),{code:"NOT_FOUND"});if(!Me(y.clientType)&&pe(y.clientType).length===0)throw Object.assign(new Error(`client type "${y.clientType??""}" does not support Grix relay`),{code:"UNSUPPORTED_CLIENT_TYPE"});const O=await d.runExclusive(r,async()=>{const w=d.epoch(r),v=R(r);if(!v)throw Object.assign(new Error(`Agent "${r}" not found`),{code:"NOT_FOUND"});const re=String(v.agentId??"").trim();if(!re)throw new fe(`local agent "${r}" has no agent_id registered`,"MISSING_AGENT_ID");const ne=d.waitCancelled(r,w);let C;try{C=await Promise.race([o.fetchRelayCredential(r,{model:p}),ne.promise.then(()=>{throw new he("relay enable cancelled by a later disable","CANCELLED")})])}finally{ne.dispose()}d.assertCurrent(r,w);const{restarted:xe,busy:Pe,pending:oe}=await ue(m,o,R,E,{localName:r,agentId:re,virtualKey:C.apiKey,anthropicBaseUrl:C.anthropicBaseUrl,openaiBaseUrl:C.openaiBaseUrl,model:p,...C.directRelay!==void 0?{directRelay:C.directRelay}:{}},(Ie,_e,ke)=>o.setAgentProvider(Ie,_e,{deferRestart:ke?.deferRestart===!0}),{store:k,secrets:N,direct:L});if(d.epoch(r)!==w)throw await Q(K(),E,{agentName:r,target:"off"}),new he("relay enable cancelled by a later disable","CANCELLED");return{...n(),restarted:xe,busy:Pe,...oe?{pending:oe}:{}}});return o.reportRelayStateLocalChange(r),O},setAgentRelayCredential:async(r,a)=>{const p=f(),m=o.getAgentsStatus(),{restarted:E,busy:R,pending:y}=await ue(p,o,P=>m.find(O=>O.name===P),{info:P=>i.info("main",P),warn:P=>i.warn("main",P)},{localName:r,agentId:a.agentId,virtualKey:a.virtualKey,anthropicBaseUrl:a.anthropicBaseUrl,openaiBaseUrl:a.openaiBaseUrl,model:a.model,...a.directRelay!==void 0?{directRelay:a.directRelay}:{}},(P,O,w)=>o.setAgentProvider(P,O,{deferRestart:w?.deferRestart===!0}),{store:k,secrets:N,direct:L});return o.reportRelayStateLocalChange(r),{...n(),restarted:E,busy:R,...y?{pending:y}:{}}},disableAll:async()=>{const r=f(),a={info:m=>i.info("main",m),warn:m=>i.warn("main",m)},p=new Set([...r.getRelayAgents(),...o.getDirectRelayConfigAgentNames(),...Object.keys(k.list())]);for(const m of p)d.cancel(m);for(const m of p)await d.runExclusive(m,()=>Q(K(),a,{agentName:m,target:"off"})),o.reportRelayStateLocalChange(m);return await ge(r,o),n()},setRoute:async(r,a)=>{const p=a,m=f();return m.setRoute({routeKey:r,targetBaseUrl:p.targetBaseUrl,...p.headers?{headers:p.headers}:{},...p.model?{model:p.model}:{},...p.modelMap?{modelMap:p.modelMap}:{},...p.passthrough?{passthrough:!0}:{},...p.relayOnly?{relayOnly:!0}:{},...p.codexResponsesToChat?{codexResponsesToChat:!0}:{}}),await m.persistConfig(),n()},deleteRoute:async r=>{const a=f();a.deleteRoute(r),await a.persistConfig()},setDefaultRoute:async r=>{const a=f();return a.setDefaultRouteKey(r),await a.persistConfig(),n()},setInterceptHosts:async r=>{const a=f();return a.setInterceptHosts(r),await a.persistConfig(),n()}};H=A,x.setProxyHandler(A),o.setRelayStateApplier({getLocalState:r=>{const a=f();if(a.getRelayAgents().includes(r)){const m=o.getAgentsStatus().find(y=>y.name===r),E=`grix-gateway-${String(m?.clientType??"").trim().toLowerCase()}`;return{enabled:!0,model:a.getConfigSnapshot().routes?.find(y=>y.routeKey===E)?.model?.trim()||void 0}}const p=o.getAgentProvider(r);return p?.api_key?.trim()?{enabled:!0,model:p.model?.trim()||void 0}:{enabled:!1}},applyEnable:async(r,a,p)=>{const m=o.getAgentsStatus().find(y=>y.name===r),E=String(m?.agentId??"").trim();if(!E)throw new fe(`local agent "${r}" has no agent_id registered`,"MISSING_AGENT_ID");const R=await A.setAgentRelayCredential(r,{agentId:E,virtualKey:a.apiKey,anthropicBaseUrl:a.anthropicBaseUrl,openaiBaseUrl:a.openaiBaseUrl,model:p??a.model,...a.directRelay!==void 0?{directRelay:a.directRelay}:{}});return{restarted:R.restarted===!0,busy:R.busy===!0,...R.pending?{pending:R.pending}:{}}},applyDisable:async r=>{const a=await A.setAgentRelay(r,!1);return{restarted:a.restarted===!0,busy:a.busy===!0,...a.pending?{pending:a.pending}:{}}}})}M.setStatusProvider(()=>o.getAgentsStatus()),M.setMetaProvider(()=>{const e=o.getAgentsStatus(),n=Le();return{ws:{connected:e.filter(d=>d.wsConnected===!0).length,total:e.length},upgrade:St(),log:{dir:n.logDir,file:n.logFile,primary_dir:n.primaryLogDir,degraded:n.degraded,using_fallback:n.usingFallback,...n.degradeReason?{degrade_reason:n.degradeReason}:{}}}});const X=new ot(b.join(c.dataDir,"remote-admin.json"));if(o.setRemoteAdminGate(()=>X.isEnabled()),await o.start(Dt),U.length>0){const e=o.getAgentsStatus();for(const n of U){const d=e.find(r=>r.name===n);if(!d)continue;const A=pe(d.clientType);A.length!==0&&await S.setAgentRelayEnabled(n,!0,{relayHosts:A}).catch(r=>{i.warn("main",`failed to reconcile relay hosts for "${n}": ${r}`)})}}me(S,L,k);const ee=parseInt(D["admin-port"]??process.env.GRIX_ADMIN_PORT??"19580",10);x.setAgentHandler({list:()=>o.getAgentsStatus(),add:e=>o.addAgent(e),remove:e=>o.removeAgent(e),restart:e=>o.restartAgent(e),reload:()=>o.reload()}),x.setUpgradeHandler({check:()=>o.checkUpgrade(),trigger:()=>o.triggerUpgrade()}),x.setProbeHandler({probeAll:e=>o.probeAll(e),probeOne:(e,n)=>o.probeOne(e,n)}),x.setRemoteAdminHandler({isEnabled:()=>X.isEnabled(),setEnabled:e=>{const n=X.setEnabled(e);return i.info("main",`remote admin ${n?"enabled":"disabled"} via admin API`),n}}),x.setInstallHandler({listInstallable:()=>o.listInstallable(),installAgent:e=>o.installAgent(e),getInstallProgress:e=>o.getInstallProgress(e)});const te={listAgents:()=>o.getAgentsStatus(),enableManaged:(e,n,d)=>{if(!H)throw new ye(`agent "${e}" needs the MITM proxy for relay, but it is not running`,"PROXY_UNAVAILABLE");return H.setAgentRelayCredential(e,{agentId:n,virtualKey:d.virtualKey,anthropicBaseUrl:d.anthropicBaseUrl,openaiBaseUrl:d.openaiBaseUrl,model:d.model,...d.directRelay!==void 0?{directRelay:d.directRelay}:{}})},disableManaged:e=>{if(!H)throw new ye(`agent "${e}" needs the MITM proxy for relay, but it is not running`,"PROXY_UNAVAILABLE");return H.setAgentRelay(e,!1)},enableHermesProfile:(e,n)=>ut({agentId:e,baseUrl:n.openaiBaseUrl??"",virtualKey:n.virtualKey,model:n.model??""}),disableHermesProfile:e=>ft(e)};x.setRelayCredentialHandler({listHermesProfiles:()=>ht(),enable:async(e,n)=>{const{target:d,result:A}=await wt(te,e,n);return{target:d,...A}},disable:async e=>{const{target:n,result:d}=await yt(te,e);return{target:n,...d}}});{const e=await se({label:"admin",port:ee,envVar:"GRIX_ADMIN_PORT",cliFlag:"admin-port",start:n=>x.start(n)});e&&await De(e)}const ve=b.join(c.dataDir,"admin-token"),be=b.join(c.dataDir,"admin-port");st(ve,Re),ae(be,String(ee),"utf-8"),await G(c.daemonStatusFile,{state:"running",pid:process.pid,instance_id:$,updated_at:Date.now()}),process.send&&process.send("ready"),i.info("main","grix-connector ready")}bt().catch(async t=>{const s=`Fatal: ${t instanceof Error?t.stack??t.message:String(t)}`;try{process.stderr.write(`${s}
|
|
43
|
-
`)}catch{}
|
|
39
|
+
right-click the terminal and select "Run as administrator".`);const t=Y(),s=E["config-dir"]??(E.profile?b.join(t.configDir,E.profile):void 0),g=b.resolve(process.argv[1]||`${t.rootDir}/dist/grix.js`),f=new de({cliPath:g,nodePath:process.execPath});try{let l;switch(I){case"start":{const m=await f.healLegacyState({rootDir:t.rootDir});(await f.status({rootDir:t.rootDir})).installed?l=await f.start({rootDir:t.rootDir}):l=await f.install({rootDir:t.rootDir,configDir:s??m.configDir}),m.healed&&(l={...l,legacy_heal:m.reasons})}break;case"stop":l=await f.stop({rootDir:t.rootDir});break;case"restart":if(!(await f.status({rootDir:t.rootDir})).installed)l=await f.install({rootDir:t.rootDir,configDir:s});else{const D=process.platform==="darwin"&&Je();D&&console.warn(Se),l=await f.restart({rootDir:t.rootDir}),D&&(l={...l,mode:"kickstart",note:Se})}break;case"status":l=await f.status({rootDir:t.rootDir});{const m=nt(t.dataDir);m&&(l={...l,duplicate_daemon:m})}break}console.log(JSON.stringify(l,null,2)),process.exit(0)}catch(l){console.error(`${I} failed: ${l instanceof Error?l.message:l}`),process.exit(1)}}else I&&(console.error(`Unknown command: ${I}
|
|
40
|
+
Valid commands: ${Re.join(", ")}`),process.exit(1));const c=Y(),vt=E["config-dir"]??(E.profile?`${c.configDir}/${E.profile}`:void 0),o=new Te({requestGracefulShutdown:t=>{k(t)},onTransactionSettled:()=>{J({rootDir:c.rootDir,requestGracefulShutdown:()=>{k("wrapper-migration")}}).then(t=>{t.handoffStarted&&i.info("main","Wrapper handoff started after the upgrade transaction settled")}).catch(t=>{i.warn("main",`Post-upgrade wrapper migration failed: ${t instanceof Error?t.message:t}`)})}}),G=new Oe,Ee=ct(),x=new st(Ee);let W=!1,$;function K(t,s){const g=q(),f=process.env.GRIX_LAUNCHER_VERSION;if(!g||!f)return;const l=s instanceof Error?s.stack??s.message:String(s);je(g,f,`${t}: ${l}`)}function De(t,s){ot(c.dataDir,{holder_pid:t.pid,holder_command_line:t.command_line,yielded_pid:process.pid,yielded_command_line:Ye(process.pid)}),process.stderr.write(`${s}
|
|
41
|
+
`),i.warn("main",s);const g=q();g&&pe(g)}function bt(t){const s=`another grix-connector daemon (pid ${t.pid}) is already serving ${c.rootDir} and answering /healthz; this process yields instead of taking over. A second supervisor is starting duplicate daemons \u2014 check for a leftover wrapper, a duplicate logon task, or a desktop app launching its own copy.`;De(t,s),process.exit(0)}function xt(t,s){const g=`${s.label} \u7AEF\u53E3 ${s.port} \u5DF2\u88AB\u5360\u7528\uFF0C\u4E14 daemon \u9501\u4ECD\u7531\u53E6\u4E00\u4E2A\u5B58\u6D3B\u5B9E\u4F8B (pid ${t.pid}) \u6301\u6709\uFF1A\u672C\u8FDB\u7A0B\u6309\u7BA1\u7406\u6027\u9000\u51FA\u8BA9\u4F4D\uFF0C\u4E0D\u8BA1\u4E3A\u5D29\u6E83\u3002 \u8FD9\u53F0\u673A\u5668\u4E0A\u6709\u7B2C\u4E8C\u4E2A supervisor \u5728\u91CD\u590D\u62C9\u8D77 daemon\u2014\u2014\u68C0\u67E5\u6B8B\u7559\u7684 wrapper\u3001\u91CD\u590D\u7684\u767B\u5F55\u4EFB\u52A1\uFF0C\u6216\u684C\u9762\u7AEF\u53E6\u8D77\u7684\u526F\u672C\u3002`;De(t,g),le()===process.pid&&T(),process.exit(0)}async function Ae(t){if(t.kind==="in_use"){const g=et(c.daemonLockFile);g&&(await j(),xt(g,t))}process.stderr.write(t.message+`
|
|
42
|
+
`),i.error("main",t.message.replace(/\n/g," \u2014 ")),K("port_bind",t.message);const s=z(c.daemonLockFile);s?.pid===process.pid&&s.instance_id===$&&await B(c.daemonStatusFile,{state:"failed",pid:process.pid,instance_id:$,updated_at:Date.now(),reason:`port_bind_${t.kind}:${t.label}:${t.port}`}).catch(()=>{}),await j(),N(c.daemonLockFile).catch(()=>{}),T(),process.exit(1)}async function k(t){if(W)return;W=!0,i.info("main",`Received ${t}, shutting down...`),G.markShuttingDown();const s=q();s&&pe(s);const g=t==="upgrade-switch"?Me:t==="launcher-unhealthy"?Be:null,f=g??2,l=t==="uncaughtException"||t==="unhandledRejection",m=setTimeout(()=>{i.error("main","Shutdown timed out, forcing exit"),N(c.daemonLockFile).catch(()=>{}),T(),process.exit(f)},1e4);try{await o.stop(),await h()?.stop().catch(()=>{}),await x.stop(),await G.stop(),await j(),await N(c.daemonLockFile),await rt(c.daemonStatusFile).catch(()=>{}),clearTimeout(m),T(),i.info("main","Shutdown complete"),process.exit(g??(l?2:0))}catch(D){i.error("main",`Shutdown error: ${D}`),N(c.daemonLockFile).catch(()=>{}),T(),process.exit(f)}}async function Pt(){const t=at();t.lap("boot"),$e(),Le(),He(c.stdoutLogFile,c.stderrLogFile),se(!1);try{$=(await ze(c.daemonLockFile,c.rootDir,2,{isHolderServing:Qe(c.dataDir)})).instance_id}catch(e){e instanceof Ze&&bt(e.holder),console.error(e instanceof Error?e.message:e),process.exit(1)}if(t.lap("lock"),Ve()){const e=qe(c.rootDir,"win32");await Ke(e,{platform:"win32"})}t.lap("sweep"),await dt(),Fe(),t.lap("sentry"),i.info("main",`grix-connector starting (PID ${process.pid})`);try{Ne({info:e=>i.info("main",e),warn:e=>i.warn("main",e)})}catch(e){i.warn("main",`orphan Claude cleanup failed: ${e instanceof Error?e.message:String(e)}`)}t.lap("orphan"),await B(c.daemonStatusFile,{state:"starting",pid:process.pid,instance_id:$,updated_at:Date.now()}),process.env.GRIX_LAUNCHER_MANAGED!=="1"&&await new de({cliPath:b.resolve(process.argv[1]??""),nodePath:process.execPath}).adoptLauncher(c.rootDir).then(e=>{e&&i.info("main","Service definition now points at the version-store launcher")}).catch(e=>{i.warn("main",`Launcher adoption failed: ${e instanceof Error?e.message:e}`)}),t.lap("adopt");const s=await J({rootDir:c.rootDir,requestGracefulShutdown:()=>{k("wrapper-migration")}}).catch(e=>(i.warn("main",`Windows wrapper migration failed: ${e instanceof Error?e.message:e}`),null));if(t.lap("migrate"),s?.handoffStarted)return;process.platform==="win32"&&process.env.GRIX_LAUNCHER_MANAGED!=="1"&&setInterval(()=>{W||J({rootDir:c.rootDir,requestGracefulShutdown:()=>{k("wrapper-migration")}}).then(n=>{n.handoffStarted&&i.info("main","Wrapper handoff started by the periodic migration retry")}).catch(n=>{i.warn("main",`Periodic wrapper migration failed: ${n instanceof Error?n.message:n}`)})},We).unref();const g=parseInt(E["health-port"]??process.env.GRIX_HEALTH_PORT??"19579",10);{const e=await ce({label:"health",port:g,envVar:"GRIX_HEALTH_PORT",cliFlag:"health-port",start:n=>G.start(n)});e&&await Ae(e)}const f=b.join(c.dataDir,"health-port");ie(f,String(g),"utf-8"),t.lap("health"),process.on("SIGINT",()=>k("SIGINT")),process.on("SIGTERM",()=>k("SIGTERM")),process.on("SIGHUP",()=>{W||(i.info("main","Received SIGHUP, reloading config..."),o.reload().then(e=>i.info("main",`reload done: ${JSON.stringify(e)}`)).catch(e=>i.error("main",`reload failed: ${e instanceof Error?e.message:e}`)))});let l="",m=0,D;process.on("uncaughtException",e=>{const n=e instanceof Error?e.stack??e.message:String(e);n===l?(m++,(m<=3||m%100===0)&&i.error("main",`Uncaught exception (x${m}): ${n}`)):(m>3&&i.error("main",`Previous exception repeated ${m} times total`),l=n,m=1,i.error("main",`Uncaught exception: ${e instanceof Error?e.stack:e}`),D||(D=setTimeout(()=>{m>3&&i.error("main",`Previous exception repeated ${m} times total`),l="",m=0,D=void 0},1e4).unref())),!ve(e)&&(Q(e,"uncaughtException"),K("uncaughtException",e),k("uncaughtException"))}),process.on("unhandledRejection",e=>{i.error("main",`Unhandled rejection: ${e}`),!ve(e)&&(Q(e,"unhandledRejection"),K("unhandledRejection",e),k("unhandledRejection"))});const L=gt(c.dataDir);await L.clearRuntimeState();const _=new mt(b.join(c.dataDir,"proxy","relay-state.json"),{warn:e=>i.warn("main",e)}),M=new ut(b.join(c.dataDir,"secrets"));o.setRelaySecretResolver(e=>M.get(e));const U={hasDirectConfig:e=>o.hasDirectRelayConfig(e),clearDirectConfig:(e,n)=>o.setAgentProvider(e,void 0,{deferRestart:n?.deferRestart===!0})},X=()=>({pm:h(),agents:o,direct:U,store:_,secrets:M}),H=L.getRelayAgents();if(H.length>0)try{await L.startIfAnyRelayAgent(),i.info("main",`mitm proxy started for relay agents: ${H.join(", ")} (per-agent; others stay direct)`)}catch(e){i.error("main",`mitm proxy FAILED to start (relay agents: ${H.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 i.info("main",'mitm proxy idle (no agent has Grix relay enabled; enable: PUT /api/proxy/agents/<name>/enabled {"enabled":true})');let O=null;if(h()){const e=async()=>{const r=h();r&&await me(r,o)&&i.info("main","no agent uses Grix relay anymore; mitm proxy stopped")};o.setRelayEnvSettledHandler(()=>{const r=h();r&&ue(r,U,_),e().catch(a=>{i.warn("main",`failed to stop idle mitm proxy: ${a}`)})});const n=()=>{const r=h(),a=r.getRelayAgents(),p=r.getDegradedRelayAgents();return{enabled:a.length>0,relayAgents:a,staleRelayAgents:o.getAgentsWithStaleRelayEnv(),degradedRelayAgents:p,relayState:_.list(),runtime:r.getRuntimeInfo(),config:r.getConfigSnapshot()}},d=new ft,A={status:()=>n(),setAgentRelay:async(r,a,p)=>{const u=h(),R={info:w=>i.info("main",w),warn:w=>i.warn("main",w)},S=w=>o.getAgentsStatus().find(v=>v.name===w),y=S(r);if(!a){d.cancel(r);const w=await d.runExclusive(r,async()=>{const v=await Z(X(),R,{agentName:r,target:"off"});return{...n(),restarted:v.restarted,busy:v.busy,...v.pending?{pending:v.pending}:{}}});return o.reportRelayStateLocalChange(r),w}if(!y)throw Object.assign(new Error(`Agent "${r}" not found`),{code:"NOT_FOUND"});if(!Ge(y.clientType)&&ge(y.clientType).length===0)throw Object.assign(new Error(`client type "${y.clientType??""}" does not support Grix relay`),{code:"UNSUPPORTED_CLIENT_TYPE"});const F=await d.runExclusive(r,async()=>{const w=d.epoch(r),v=S(r);if(!v)throw Object.assign(new Error(`Agent "${r}" not found`),{code:"NOT_FOUND"});const ne=String(v.agentId??"").trim();if(!ne)throw new he(`local agent "${r}" has no agent_id registered`,"MISSING_AGENT_ID");const oe=d.waitCancelled(r,w);let C;try{C=await Promise.race([o.fetchRelayCredential(r,{model:p}),oe.promise.then(()=>{throw new ye("relay enable cancelled by a later disable","CANCELLED")})])}finally{oe.dispose()}d.assertCurrent(r,w);const{restarted:Pe,busy:Ie,pending:ae}=await fe(u,o,S,R,{localName:r,agentId:ne,virtualKey:C.apiKey,anthropicBaseUrl:C.anthropicBaseUrl,openaiBaseUrl:C.openaiBaseUrl,model:p,...C.directRelay!==void 0?{directRelay:C.directRelay}:{}},(ke,_e,Ce)=>o.setAgentProvider(ke,_e,{deferRestart:Ce?.deferRestart===!0}),{store:_,secrets:M,direct:U});if(d.epoch(r)!==w)throw await Z(X(),R,{agentName:r,target:"off"}),new ye("relay enable cancelled by a later disable","CANCELLED");return{...n(),restarted:Pe,busy:Ie,...ae?{pending:ae}:{}}});return o.reportRelayStateLocalChange(r),F},setAgentRelayCredential:async(r,a)=>{const p=h(),u=o.getAgentsStatus(),{restarted:R,busy:S,pending:y}=await fe(p,o,P=>u.find(F=>F.name===P),{info:P=>i.info("main",P),warn:P=>i.warn("main",P)},{localName:r,agentId:a.agentId,virtualKey:a.virtualKey,anthropicBaseUrl:a.anthropicBaseUrl,openaiBaseUrl:a.openaiBaseUrl,model:a.model,...a.directRelay!==void 0?{directRelay:a.directRelay}:{}},(P,F,w)=>o.setAgentProvider(P,F,{deferRestart:w?.deferRestart===!0}),{store:_,secrets:M,direct:U});return o.reportRelayStateLocalChange(r),{...n(),restarted:R,busy:S,...y?{pending:y}:{}}},disableAll:async()=>{const r=h(),a={info:u=>i.info("main",u),warn:u=>i.warn("main",u)},p=new Set([...r.getRelayAgents(),...o.getDirectRelayConfigAgentNames(),...Object.keys(_.list())]);for(const u of p)d.cancel(u);for(const u of p)await d.runExclusive(u,()=>Z(X(),a,{agentName:u,target:"off"})),o.reportRelayStateLocalChange(u);return await me(r,o),n()},setRoute:async(r,a)=>{const p=a,u=h();return u.setRoute({routeKey:r,targetBaseUrl:p.targetBaseUrl,...p.headers?{headers:p.headers}:{},...p.model?{model:p.model}:{},...p.modelMap?{modelMap:p.modelMap}:{},...p.passthrough?{passthrough:!0}:{},...p.relayOnly?{relayOnly:!0}:{},...p.codexResponsesToChat?{codexResponsesToChat:!0}:{}}),await u.persistConfig(),n()},deleteRoute:async r=>{const a=h();a.deleteRoute(r),await a.persistConfig()},setDefaultRoute:async r=>{const a=h();return a.setDefaultRouteKey(r),await a.persistConfig(),n()},setInterceptHosts:async r=>{const a=h();return a.setInterceptHosts(r),await a.persistConfig(),n()}};O=A,x.setProxyHandler(A),o.setRelayStateApplier({getLocalState:r=>{const a=h();if(a.getRelayAgents().includes(r)){const u=o.getAgentsStatus().find(y=>y.name===r),R=`grix-gateway-${String(u?.clientType??"").trim().toLowerCase()}`;return{enabled:!0,model:a.getConfigSnapshot().routes?.find(y=>y.routeKey===R)?.model?.trim()||void 0}}const p=o.getAgentProvider(r);return p?.api_key?.trim()?{enabled:!0,model:p.model?.trim()||void 0}:{enabled:!1}},applyEnable:async(r,a,p)=>{const u=o.getAgentsStatus().find(y=>y.name===r),R=String(u?.agentId??"").trim();if(!R)throw new he(`local agent "${r}" has no agent_id registered`,"MISSING_AGENT_ID");const S=await A.setAgentRelayCredential(r,{agentId:R,virtualKey:a.apiKey,anthropicBaseUrl:a.anthropicBaseUrl,openaiBaseUrl:a.openaiBaseUrl,model:p??a.model,...a.directRelay!==void 0?{directRelay:a.directRelay}:{}});return{restarted:S.restarted===!0,busy:S.busy===!0,...S.pending?{pending:S.pending}:{}}},applyDisable:async r=>{const a=await A.setAgentRelay(r,!1);return{restarted:a.restarted===!0,busy:a.busy===!0,...a.pending?{pending:a.pending}:{}}}})}G.setStatusProvider(()=>o.getAgentsStatus()),G.setMetaProvider(()=>{const e=o.getAgentsStatus(),n=Ue();return{ws:{connected:e.filter(d=>d.wsConnected===!0).length,total:e.length},upgrade:Et(),log:{dir:n.logDir,file:n.logFile,primary_dir:n.primaryLogDir,degraded:n.degraded,using_fallback:n.usingFallback,...n.degradeReason?{degrade_reason:n.degradeReason}:{}}}});const V=new it(b.join(c.dataDir,"remote-admin.json"));if(o.setRemoteAdminGate(()=>V.isEnabled()),t.lap("setup"),await o.start(vt),t.lap("agents"),H.length>0){const e=o.getAgentsStatus();for(const n of H){const d=e.find(r=>r.name===n);if(!d)continue;const A=ge(d.clientType);A.length!==0&&await L.setAgentRelayEnabled(n,!0,{relayHosts:A}).catch(r=>{i.warn("main",`failed to reconcile relay hosts for "${n}": ${r}`)})}}ue(L,U,_);const te=parseInt(E["admin-port"]??process.env.GRIX_ADMIN_PORT??"19580",10);x.setAgentHandler({list:()=>o.getAgentsStatus(),add:e=>o.addAgent(e),remove:e=>o.removeAgent(e),restart:e=>o.restartAgent(e),reload:()=>o.reload()}),x.setUpgradeHandler({check:()=>o.checkUpgrade(),trigger:()=>o.triggerUpgrade()}),x.setProbeHandler({probeAll:e=>o.probeAll(e),probeOne:(e,n)=>o.probeOne(e,n)}),x.setRemoteAdminHandler({isEnabled:()=>V.isEnabled(),setEnabled:e=>{const n=V.setEnabled(e);return i.info("main",`remote admin ${n?"enabled":"disabled"} via admin API`),n}}),x.setInstallHandler({listInstallable:()=>o.listInstallable(),installAgent:e=>o.installAgent(e),getInstallProgress:e=>o.getInstallProgress(e)});const re={listAgents:()=>o.getAgentsStatus(),enableManaged:(e,n,d)=>{if(!O)throw new we(`agent "${e}" needs the MITM proxy for relay, but it is not running`,"PROXY_UNAVAILABLE");return O.setAgentRelayCredential(e,{agentId:n,virtualKey:d.virtualKey,anthropicBaseUrl:d.anthropicBaseUrl,openaiBaseUrl:d.openaiBaseUrl,model:d.model,...d.directRelay!==void 0?{directRelay:d.directRelay}:{}})},disableManaged:e=>{if(!O)throw new we(`agent "${e}" needs the MITM proxy for relay, but it is not running`,"PROXY_UNAVAILABLE");return O.setAgentRelay(e,!1)},enableHermesProfile:(e,n)=>ht({agentId:e,baseUrl:n.openaiBaseUrl??"",virtualKey:n.virtualKey,model:n.model??""}),disableHermesProfile:e=>yt(e)};x.setRelayCredentialHandler({listHermesProfiles:()=>wt(),enable:async(e,n)=>{const{target:d,result:A}=await Rt(re,e,n);return{target:d,...A}},disable:async e=>{const{target:n,result:d}=await St(re,e);return{target:n,...d}}});{const e=await ce({label:"admin",port:te,envVar:"GRIX_ADMIN_PORT",cliFlag:"admin-port",start:n=>x.start(n)});e&&await Ae(e)}const be=b.join(c.dataDir,"admin-token"),xe=b.join(c.dataDir,"admin-port");lt(be,Ee),ie(xe,String(te),"utf-8"),t.lap("admin"),await B(c.daemonStatusFile,{state:"running",pid:process.pid,instance_id:$,updated_at:Date.now()}),i.info("main",`startup phases: ${t.summary()}`),process.send&&process.send("ready"),i.info("main","grix-connector ready")}Pt().catch(async t=>{const s=`Fatal: ${t instanceof Error?t.stack??t.message:String(t)}`;try{process.stderr.write(`${s}
|
|
43
|
+
`)}catch{}se(!1),i.error("main",s),Q(t,"startup"),K("startup",t);const g=z(c.daemonLockFile);g?.pid===process.pid&&g.instance_id===$&&await B(c.daemonStatusFile,{state:"failed",pid:process.pid,instance_id:g.instance_id,updated_at:Date.now(),reason:"startup_error"}).catch(()=>{}),await j(),N(c.daemonLockFile).catch(()=>{}),T(),process.exit(1)});const It=new Set(["ECONNRESET","ECONNREFUSED","ETIMEDOUT","EPIPE","EAI_AGAIN","ENOTFOUND","EHOSTUNREACH","ENETUNREACH","EIO"]);function ve(t){return pt(t)?!0:t instanceof Error&&"code"in t?It.has(t.code):!1}
|
package/dist/log.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import{createWriteStream as g,mkdirSync as l,existsSync as f}from"node:fs";import{join as
|
|
2
|
-
`)},error(o,r,...
|
|
1
|
+
import{createWriteStream as g,mkdirSync as l,existsSync as f}from"node:fs";import{join as t}from"node:path";import{homedir as m}from"node:os";const i=t(m(),".grix"),s={base:i,config:t(i,"config"),log:t(i,"log"),data:t(i,"data")};function S(){for(const o of Object.values(s))f(o)||l(o,{recursive:!0})}let a=null;function $(){const o=new Date().toISOString().slice(0,10),r=t(s.log,`grix-acp-${o}.log`);a=g(r,{flags:"a"})}function c(){return new Date().toISOString().slice(11,19)}const u={info(o,r,...n){const e=`${c()} [${o}] ${r}${n.length?" "+n.map(String).join(" "):""}`;console.log(e),a?.write(e+`
|
|
2
|
+
`)},error(o,r,...n){const e=`${c()} [${o}] ERROR ${r}${n.length?" "+n.map(String).join(" "):""}`;console.error(e),a?.write(e+`
|
|
3
3
|
`)}};export{s as GRIX_PATHS,S as ensureGrixDirs,$ as initLogger,u as log};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import*as
|
|
1
|
+
import*as i from"node:net";const e={bind:"127.0.0.1",port:0,endpoint:"/mcp",sessionTimeoutMs:18e5,invokeTimeoutMs:3e4};function n(o){const u={bind:o?.bind??e.bind,port:o?.port??e.port,endpoint:o?.endpoint??e.endpoint,sessionTimeoutMs:o?.sessionTimeoutMs??e.sessionTimeoutMs,invokeTimeoutMs:o?.invokeTimeoutMs??e.invokeTimeoutMs,allowedOrigins:o?.allowedOrigins,allowedHosts:o?.allowedHosts};return s(u.bind),u.port!==0&&t(u.port),r(u.sessionTimeoutMs),u}function s(o){if(!o||!i.isIPv4(o)&&!i.isIPv6(o))throw new Error(`\u914D\u7F6E\u6821\u9A8C\u5931\u8D25: bind \u5730\u5740 "${o}" \u4E0D\u662F\u5408\u6CD5\u7684 IPv4 \u6216 IPv6 \u5730\u5740`)}function t(o){if(!Number.isInteger(o)||o<1||o>65535)throw new Error(`\u914D\u7F6E\u6821\u9A8C\u5931\u8D25: port \u503C ${o} \u4E0D\u5728\u5408\u6CD5\u8303\u56F4 1-65535 \u5185\u6216\u4E0D\u662F\u6574\u6570`)}function r(o){if(!Number.isInteger(o)||o<1e3||o>864e5)throw new Error(`\u914D\u7F6E\u6821\u9A8C\u5931\u8D25: session_timeout_ms \u503C ${o} \u4E0D\u5728\u5408\u6CD5\u8303\u56F4 1000-86400000 \u5185`)}export{n as createDefaultGatewayConfig};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
const
|
|
1
|
+
const r=3e4;class c{connectionManager;onDisconnected;bindings=new Map;constructor(n,i){this.connectionManager=n,this.onDisconnected=i}async bind(n,i){if(this.bindings.has(n))throw new Error(`Session ${n} is already bound to a connection`);const e=await this.connectWithTimeout(i),t=[],s=e.onDisconnected(()=>{this.removeBinding(n),this.onDisconnected(n)});return t.push(s),this.bindings.set(n,{sessionId:n,handle:e,subscriptions:t}),e}getHandle(n){return this.bindings.get(n)?.handle}unbind(n){const i=this.bindings.get(n);if(i){this.bindings.delete(n);for(const e of i.subscriptions)e();i.handle.disconnect()}}unbindAll(){const n=[...this.bindings.keys()];for(const i of n)this.unbind(i)}connectWithTimeout(n){return new Promise((i,e)=>{let t=!1;const s=setTimeout(()=>{t||(t=!0,e(new Error("Connection bind timeout after 30000ms")))},3e4);this.connectionManager.connect({agentId:n.agentId,apiKey:n.apiKey,url:n.wsUrl,clientType:n.clientType,capabilities:["agent_invoke"],adapterHint:`${n.clientType}/base`},{maxRetries:0}).then(o=>{t?o.disconnect():(t=!0,clearTimeout(s),i(o))}).catch(o=>{t||(t=!0,clearTimeout(s),e(o))})})}removeBinding(n){const i=this.bindings.get(n);if(i){this.bindings.delete(n);for(const e of i.subscriptions)e()}}}export{c as ConnectionBindingImpl};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{toolCallToInvoke as i}from"../../core/mcp/tools.js";import{ToolRegistryImpl as l}from"./tool-registry.js";import{validateToolArgs as a}from"./tool-schemas.js";import{isEventTool as p,executeEventTool as d}from"./event-tool-executor.js";class y{registry;constructor(){this.registry=new l}async execute(
|
|
1
|
+
import{toolCallToInvoke as i}from"../../core/mcp/tools.js";import{ToolRegistryImpl as l}from"./tool-registry.js";import{validateToolArgs as a}from"./tool-schemas.js";import{isEventTool as p,executeEventTool as d}from"./event-tool-executor.js";class y{registry;constructor(){this.registry=new l}async execute(t,e,r,n){if(!this.registry.hasTool(e))return this.errorResult(`\u672A\u77E5\u5DE5\u5177: ${e}`);const s=a(e,r);if(!s.valid)return this.errorResult(`\u53C2\u6570\u6821\u9A8C\u5931\u8D25: ${s.error}`);if(t.status!=="ready")return this.errorResult(`\u8FDE\u63A5\u4E0D\u53EF\u7528: \u5F53\u524D\u72B6\u6001\u4E3A ${t.status}`);if(p(e))return this.executeEventTool(t,e,r);const o=i(e,r);try{const u=await t.agentInvoke(o.action,o.params,n);return this.normalizeResult(u)}catch(u){const c=u instanceof Error?u.message:String(u);return c.toLowerCase().includes("timeout")?this.errorResult(`\u8C03\u7528\u8D85\u65F6: ${c}`):this.errorResult(`\u8C03\u7528\u5931\u8D25: ${c}`)}}normalizeResult(t){if(t==null||typeof t!="object")return this.successResult(t??null);const e=t,r=typeof e.code=="number"?e.code:0;if(r===0){const s="data"in e?e.data:null;return this.successResult(s??null)}const n=typeof e.msg=="string"?e.msg:"\u672A\u77E5\u9519\u8BEF";return this.errorResult(`\u4E0A\u6E38\u9519\u8BEF [code=${r}]: ${n}`)}successResult(t){return{content:[{type:"text",text:JSON.stringify(t)}],isError:!1}}errorResult(t){return{content:[{type:"text",text:t}],isError:!0}}async executeEventTool(t,e,r){return e==="grix_access_control"?this.executeAccessControl(t,r):d(t,e,r)}async executeAccessControl(t,e){const r=String(e.action??""),n={pair_approve:"pair_approve",pair_deny:"pair_deny",allow_sender:"sender_allow",remove_sender:"sender_remove",set_policy:"policy_set"}[r];if(!n)return this.errorResult(`\u672A\u77E5 access_control action: ${r}`);const s={};e.code!=null&&(s.code=e.code),e.sender_id!=null&&(s.sender_id=e.sender_id),e.policy!=null&&(s.policy=e.policy);try{const o=await t.agentInvoke("claude_access_control",{verb:n,payload:s},3e4);return this.successResult(o)}catch(o){const u=o instanceof Error?o.message:String(o);return this.errorResult(`access_control \u8C03\u7528\u5931\u8D25: ${u}`)}}}export{y as ToolExecutorImpl};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{TOOLS as
|
|
1
|
+
import{TOOLS as s,EVENT_TOOLS as t}from"../../core/mcp/tools.js";const e=new Set(["grix_query","grix_group","grix_message_send","grix_message_unsend","grix_admin"]),r=new Set(["grix_reply","grix_complete","grix_event_ack","grix_composing","grix_access_control","grix_status"]);class a{tools;toolMap;constructor(){this.tools=[...s.filter(o=>e.has(o.name)),...t.filter(o=>r.has(o.name))],this.toolMap=new Map(this.tools.map(o=>[o.name,o]))}getTools(){return this.tools}getTool(o){return this.toolMap.get(o)}hasTool(o){return this.toolMap.has(o)}}export{a as ToolRegistryImpl};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
const o={required:["action"],properties:{action:{type:"string",enum:["contact_search","session_search","message_history","message_search"]},id:{type:"string"},keyword:{type:"string",maxLength:200},limit:{type:"integer",minimum:1,maximum:100},offset:{type:"integer",minimum:0},sessionId:{type:"string"},beforeId:{type:"string"}}},a={required:["action"],properties:{action:{type:"string",enum:["create","detail","leave","add_members","remove_members","update_member_role","update_all_members_muted","update_member_speaking","dissolve"]},sessionId:{type:"string"},name:{type:"string",maxLength:128},memberIds:{type:"array",items:{type:"string"},maxItems:100},memberTypes:{type:"array",items:{type:"integer",enum:[1,2]}},memberId:{type:"string"},role:{type:"integer",enum:[1,2]},memberType:{type:"integer"},allMembersMuted:{type:"boolean"},isSpeakMuted:{type:"boolean"},canSpeakWhenAllMuted:{type:"boolean"}}},p={required:["sessionId","content"],properties:{sessionId:{type:"string"},content:{type:"string",maxLength:1e4},msgType:{type:"integer"},quotedMessageId:{type:"string"},threadId:{type:"string"}}},m={required:["sessionId","msgId"],properties:{sessionId:{type:"string"},msgId:{type:"string"}}},g={required:["action"],properties:{action:{type:"string",enum:["create_agent","list_categories","create_category","update_category","assign_category","rotate_api_key"]},agentName:{type:"string"},introduction:{type:"string"},isMain:{type:"boolean"},agentId:{type:"string"},categoryId:{type:"string"},name:{type:"string"},parentId:{type:"string"},sortOrder:{type:"integer"}}},y={required:["session_id","text"],properties:{event_id:{type:"string"},session_id:{type:"string"},text:{type:"string",maxLength:5e4},quoted_message_id:{type:"string"},is_final:{type:"boolean"}}},d={required:["event_id","status"],properties:{event_id:{type:"string"},status:{type:"string",enum:["responded","canceled","failed"]},msg:{type:"string",maxLength:500}}},c={required:["event_id"],properties:{event_id:{type:"string"},session_id:{type:"string"}}},l={required:["session_id","active"],properties:{session_id:{type:"string"},active:{type:"boolean"},event_id:{type:"string"}}},_={required:["action"],properties:{action:{type:"string",enum:["pair_approve","pair_deny","allow_sender","remove_sender","set_policy"]},code:{type:"string"},sender_id:{type:"string"},policy:{type:"string",enum:["allowlist","open","disabled"]}}},f={required:[],properties:{}},C={grix_query:o,grix_group:a,grix_message_send:p,grix_message_unsend:m,grix_admin:g,grix_reply:y,grix_complete:d,grix_event_ack:c,grix_composing:l,grix_access_control:_,grix_status:f};function B(
|
|
1
|
+
const o={required:["action"],properties:{action:{type:"string",enum:["contact_search","session_search","message_history","message_search"]},id:{type:"string"},keyword:{type:"string",maxLength:200},limit:{type:"integer",minimum:1,maximum:100},offset:{type:"integer",minimum:0},sessionId:{type:"string"},beforeId:{type:"string"}}},a={required:["action"],properties:{action:{type:"string",enum:["create","detail","leave","add_members","remove_members","update_member_role","update_all_members_muted","update_member_speaking","dissolve"]},sessionId:{type:"string"},name:{type:"string",maxLength:128},memberIds:{type:"array",items:{type:"string"},maxItems:100},memberTypes:{type:"array",items:{type:"integer",enum:[1,2]}},memberId:{type:"string"},role:{type:"integer",enum:[1,2]},memberType:{type:"integer"},allMembersMuted:{type:"boolean"},isSpeakMuted:{type:"boolean"},canSpeakWhenAllMuted:{type:"boolean"}}},p={required:["sessionId","content"],properties:{sessionId:{type:"string"},content:{type:"string",maxLength:1e4},msgType:{type:"integer"},quotedMessageId:{type:"string"},threadId:{type:"string"}}},m={required:["sessionId","msgId"],properties:{sessionId:{type:"string"},msgId:{type:"string"}}},g={required:["action"],properties:{action:{type:"string",enum:["create_agent","list_categories","create_category","update_category","assign_category","rotate_api_key"]},agentName:{type:"string"},introduction:{type:"string"},isMain:{type:"boolean"},agentId:{type:"string"},categoryId:{type:"string"},name:{type:"string"},parentId:{type:"string"},sortOrder:{type:"integer"}}},y={required:["session_id","text"],properties:{event_id:{type:"string"},session_id:{type:"string"},text:{type:"string",maxLength:5e4},quoted_message_id:{type:"string"},is_final:{type:"boolean"}}},d={required:["event_id","status"],properties:{event_id:{type:"string"},status:{type:"string",enum:["responded","canceled","failed"]},msg:{type:"string",maxLength:500}}},c={required:["event_id"],properties:{event_id:{type:"string"},session_id:{type:"string"}}},l={required:["session_id","active"],properties:{session_id:{type:"string"},active:{type:"boolean"},event_id:{type:"string"}}},_={required:["action"],properties:{action:{type:"string",enum:["pair_approve","pair_deny","allow_sender","remove_sender","set_policy"]},code:{type:"string"},sender_id:{type:"string"},policy:{type:"string",enum:["allowlist","open","disabled"]}}},f={required:[],properties:{}},C={grix_query:o,grix_group:a,grix_message_send:p,grix_message_unsend:m,grix_admin:g,grix_reply:y,grix_complete:d,grix_event_ack:c,grix_composing:l,grix_access_control:_,grix_status:f};function B(u,t){const e=C[u];if(!e)return{valid:!1,error:`\u672A\u77E5\u5DE5\u5177: ${u}`};for(const i of e.required)if(t[i]===void 0||t[i]===null)return{valid:!1,error:`\u7F3A\u5C11\u5FC5\u586B\u53C2\u6570: ${i}`};for(const[i,r]of Object.entries(t)){if(r==null)continue;const n=e.properties[i];if(!n)continue;const s=$(i,r,n);if(s)return{valid:!1,error:s}}return{valid:!0}}function $(u,t,e){switch(e.type){case"string":if(typeof t!="string")return`\u53C2\u6570 ${u} \u7C7B\u578B\u9519\u8BEF: \u671F\u671B string\uFF0C\u5B9E\u9645 ${typeof t}`;if(e.maxLength!==void 0&&t.length>e.maxLength)return`\u53C2\u6570 ${u} \u8D85\u8FC7\u6700\u5927\u957F\u5EA6 ${e.maxLength}\uFF0C\u5B9E\u9645 ${t.length}`;if(e.enum&&!e.enum.includes(t))return`\u53C2\u6570 ${u} \u503C "${t}" \u4E0D\u5728\u5141\u8BB8\u8303\u56F4 [${e.enum.join(", ")}]`;break;case"integer":if(typeof t!="number"||!Number.isInteger(t))return`\u53C2\u6570 ${u} \u7C7B\u578B\u9519\u8BEF: \u671F\u671B integer\uFF0C\u5B9E\u9645 ${typeof t=="number"?"\u6D6E\u70B9\u6570":typeof t}`;if(e.minimum!==void 0&&t<e.minimum)return`\u53C2\u6570 ${u} \u503C ${t} \u5C0F\u4E8E\u6700\u5C0F\u503C ${e.minimum}`;if(e.maximum!==void 0&&t>e.maximum)return`\u53C2\u6570 ${u} \u503C ${t} \u5927\u4E8E\u6700\u5927\u503C ${e.maximum}`;if(e.enum&&!e.enum.includes(t))return`\u53C2\u6570 ${u} \u503C ${t} \u4E0D\u5728\u5141\u8BB8\u8303\u56F4 [${e.enum.join(", ")}]`;break;case"boolean":if(typeof t!="boolean")return`\u53C2\u6570 ${u} \u7C7B\u578B\u9519\u8BEF: \u671F\u671B boolean\uFF0C\u5B9E\u9645 ${typeof t}`;break;case"array":if(!Array.isArray(t))return`\u53C2\u6570 ${u} \u7C7B\u578B\u9519\u8BEF: \u671F\u671B array\uFF0C\u5B9E\u9645 ${typeof t}`;if(e.maxItems!==void 0&&t.length>e.maxItems)return`\u53C2\u6570 ${u} \u8D85\u8FC7\u6700\u5927\u5143\u7D20\u6570 ${e.maxItems}\uFF0C\u5B9E\u9645 ${t.length}`;if(e.items)for(let i=0;i<t.length;i++){const r=t[i];if(e.items.type==="string"&&typeof r!="string")return`\u53C2\u6570 ${u}[${i}] \u7C7B\u578B\u9519\u8BEF: \u671F\u671B string\uFF0C\u5B9E\u9645 ${typeof r}`;if(e.items.type==="integer"){if(typeof r!="number"||!Number.isInteger(r))return`\u53C2\u6570 ${u}[${i}] \u7C7B\u578B\u9519\u8BEF: \u671F\u671B integer\uFF0C\u5B9E\u9645 ${typeof r}`;if(e.items.enum&&!e.items.enum.includes(r))return`\u53C2\u6570 ${u}[${i}] \u503C ${r} \u4E0D\u5728\u5141\u8BB8\u8303\u56F4 [${e.items.enum.join(", ")}]`}}break}}export{B as validateToolArgs};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{existsSync as
|
|
2
|
-
`,"utf-8")}catch{}}export{
|
|
1
|
+
import{existsSync as u,readFileSync as i,writeFileSync as l}from"node:fs";import a from"node:path";const s=10080*60*1e3;function o(e){return a.join(e,"duplicate-daemon.json")}function c(e){const r=o(e);if(!u(r))return null;try{const t=JSON.parse(i(r,"utf-8"));return typeof t?.occurrences=="number"?t:null}catch{return null}}function f(e,r=Date.now()){const t=c(e);if(!t)return null;const n=Date.parse(t.last_yield_at);return Number.isFinite(n)&&r-n>s?null:t}function D(e,r){const t=c(e),n={...r,occurrences:(t?.occurrences??0)+1,last_yield_at:new Date().toISOString()};try{l(o(e),`${JSON.stringify(n,null,2)}
|
|
2
|
+
`,"utf-8")}catch{}}export{s as DUPLICATE_DAEMON_STATUS_TTL_MS,c as readDuplicateDaemonRecord,f as readRecentDuplicateDaemonRecord,D as recordDuplicateDaemon,o as resolveDuplicateDaemonRecordPath};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function o(r=()=>performance.now()){const t=[];let e=0;return{lap(n){const a=r();t.push(`${n}=${Math.round(a-e)}ms`),e=a},summary(){return[...t,`total=${Math.round(r())}ms`].join(" ")}}}export{o as createStartupPhaseTimer};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{existsSync as
|
|
1
|
+
import{existsSync as v,readFileSync as V}from"node:fs";import{mkdir as P,readdir as I,readFile as S,rm as y,stat as it,writeFile as $}from"node:fs/promises";import p from"node:os";import c from"node:path";import{fileURLToPath as ot,pathToFileURL as at}from"node:url";import{GRIX_HOME_ENV as T}from"../core/config/paths.js";import{isProcessRunning as R,runCommand as f,spawnDetached as _,isWindowsElevated as st,killProcessesByCommandLine as X,findProcessesByCommandLine as ct}from"./process-control.js";import{getServicePrefix as L,parseConfigDirFromPlistXML as lt,parseConfigDirFromSystemdUnit as ut,resolveBareDaemonMarkerPath as x,resolveLinuxUserUnitPath as dt,resolveMacOSLaunchAgentPath as mt}from"./service-paths.js";import{LAUNCHER_FILE as pt,readPointer as ft,versionDir as ht}from"../core/upgrade/version-store.js";function w(t){return String(t??"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}function D(t){return`'${String(t??"").replace(/'/g,"'\\''")}'`}function Q(t){return String(t??"").replace(/\\/g,"\\\\").replace(/"/g,'\\"').replace(/\n/g,"\\n").replace(/\r/g,"\\r")}function z(t){return`"${Q(t).replace(/%/g,"%%")}"`}function O(t){return String(t??"").replace(/%/g,"%%")}function gt(t){return`"${Q(t).replace(/\$/g,()=>"$$").replace(/%/g,"%%")}"`}function j(t=process.env){const r=[];for(const e of["GRIX_HEALTH_PORT","GRIX_ADMIN_PORT"]){const n=String(t[e]??"").trim();/^\d{2,5}$/.test(n)&&r.push([e,n])}return r}function J(t){return[t.nodePath,t.cliPath,...t.configDir?["--config-dir",t.configDir]:[]]}function wt(t){const r=J(t);return`<?xml version="1.0" encoding="UTF-8"?>
|
|
2
2
|
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
3
3
|
<plist version="1.0">
|
|
4
4
|
<dict>
|
|
@@ -6,7 +6,7 @@ import{existsSync as C,readFileSync as V}from"node:fs";import{mkdir as v,readdir
|
|
|
6
6
|
<string>${w(t.serviceID)}</string>
|
|
7
7
|
<key>ProgramArguments</key>
|
|
8
8
|
<array>
|
|
9
|
-
${
|
|
9
|
+
${r.map(e=>` <string>${w(e)}</string>`).join(`
|
|
10
10
|
`)}
|
|
11
11
|
</array>
|
|
12
12
|
<key>RunAtLoad</key>
|
|
@@ -22,8 +22,8 @@ ${n.map(e=>` <string>${w(e)}</string>`).join(`
|
|
|
22
22
|
<dict>
|
|
23
23
|
<key>${T}</key>
|
|
24
24
|
<string>${w(t.rootDir)}</string>
|
|
25
|
-
${j().map(([e,
|
|
26
|
-
<string>${
|
|
25
|
+
${j().map(([e,n])=>` <key>${e}</key>
|
|
26
|
+
<string>${n}</string>
|
|
27
27
|
`).join("")}${t.environmentPath?` <key>PATH</key>
|
|
28
28
|
<string>${w(t.environmentPath)}</string>
|
|
29
29
|
`:""} </dict>
|
|
@@ -33,16 +33,16 @@ ${j().map(([e,r])=>` <key>${e}</key>
|
|
|
33
33
|
<string>${w(t.stderrPath)}</string>
|
|
34
34
|
</dict>
|
|
35
35
|
</plist>
|
|
36
|
-
`}function yt(t){const
|
|
36
|
+
`}function yt(t){const r=J(t).map(e=>gt(e)).join(" ");return`[Unit]
|
|
37
37
|
Description=grix-connector daemon (${t.serviceID})
|
|
38
38
|
After=network.target
|
|
39
39
|
|
|
40
40
|
[Service]
|
|
41
41
|
Type=simple
|
|
42
|
-
ExecStart=${
|
|
42
|
+
ExecStart=${r}
|
|
43
43
|
WorkingDirectory=${O(c.dirname(t.cliPath))}
|
|
44
44
|
Environment=${z(`${T}=${t.rootDir}`)}
|
|
45
|
-
${j().map(([e,
|
|
45
|
+
${j().map(([e,n])=>`Environment=${e}=${n}
|
|
46
46
|
`).join("")}${t.environmentPath?`Environment=${z(`PATH=${t.environmentPath}`)}
|
|
47
47
|
`:""}
|
|
48
48
|
Restart=always
|
|
@@ -52,8 +52,8 @@ StandardError=append:${O(t.stderrPath)}
|
|
|
52
52
|
|
|
53
53
|
[Install]
|
|
54
54
|
WantedBy=default.target
|
|
55
|
-
`}function
|
|
56
|
-
`);return{path:e,content:
|
|
55
|
+
`}function k(t,r){const e=t.replace(/[^a-zA-Z0-9._-]/g,"_");return c.join(r,".grix",`${e}-wrapper.vbs`)}function M(t,r){const e=t.replace(/[^a-zA-Z0-9._-]/g,"_"),n=c.join(r,"AppData","Roaming","Microsoft","Windows","Start Menu","Programs","Startup");return c.join(n,`${e}.lnk`)}function m(t){return String(t??"").replace(/"/g,'""')}function A(t){return`'${String(t??"").replace(/'/g,"''")}'`}function $t(t,r){const e=c.join(c.dirname(t),c.basename(r).replace(/\.lnk$/,"-create.vbs")),n=["Option Explicit","Dim shell, shortcut",'Set shell = CreateObject("WScript.Shell")',`Set shortcut = shell.CreateShortcut("${m(r)}")`,'shortcut.TargetPath = "wscript.exe"',`shortcut.Arguments = "//B //NoLogo \\"${m(t)}\\""`,"shortcut.WindowStyle = 7","shortcut.Save",""].join(`\r
|
|
56
|
+
`);return{path:e,content:n}}async function Et(t){const{wrapperPath:r,shortcutPath:e,runCommand:n}=t,i=$t(r,e);let o="";for(let l=1;l<=3;l+=1){try{await P(c.dirname(e),{recursive:!0}),await $(i.path,i.content,"utf8");const a=await n("wscript.exe",[i.path,"//B","//NoLogo"],{allowFailure:!0}),s=String(a?.stderr??"").trim()||String(a?.stdout??"").trim(),u=Number(a?.exitCode??0);o=u===0?"wscript exited 0 but the shortcut was not created":`wscript exited with code ${u}${s?`: ${s}`:""}`}catch(a){o=a instanceof Error?a.message:String(a)}finally{await y(i.path,{force:!0}).catch(()=>{})}if(v(e))return!0}return console.warn(`Warning: failed to create Windows logon-autostart shortcut at ${e} after 3 attempts. Last error: ${o}. The daemon will NOT start automatically after the next reboot/logon. If the error points to blocked writes, check Controlled Folder Access / antivirus for the Startup folder; otherwise create the shortcut manually.`),!1}async function Pt(t){try{const r=await t("whoami",["/user","/fo","csv","/nh"],{allowFailure:!0}),e=String(r?.stdout??"").match(/"(S-1-[0-9-]+)"/);if(e)return e[1]}catch{}return null}function St(t){const r=`//B //NoLogo "${t.wrapperPath}"`;return`<?xml version="1.0" encoding="UTF-16"?>
|
|
57
57
|
<Task version="1.2" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
|
|
58
58
|
<RegistrationInfo>
|
|
59
59
|
<Description>grix-connector daemon autostart</Description>
|
|
@@ -92,17 +92,17 @@ WantedBy=default.target
|
|
|
92
92
|
<Actions Context="Author">
|
|
93
93
|
<Exec>
|
|
94
94
|
<Command>wscript.exe</Command>
|
|
95
|
-
<Arguments>${w(
|
|
95
|
+
<Arguments>${w(r)}</Arguments>
|
|
96
96
|
</Exec>
|
|
97
97
|
</Actions>
|
|
98
98
|
</Task>
|
|
99
|
-
`}async function xt(t){const{serviceID:
|
|
100
|
-
`),i=Buffer.from(
|
|
101
|
-
`)}function vt(t,
|
|
102
|
-
${
|
|
99
|
+
`}async function xt(t){const{serviceID:r,wrapperPath:e,runCommand:n}=t,i=await Pt(n)??p.userInfo().username,o=c.join(c.dirname(e),`${r}-task.xml`);try{const a=St({userId:i,wrapperPath:e});return await $(o,"\uFEFF"+a,"utf16le"),await n("schtasks",["/Create","/TN",r,"/XML",o,"/F"]),!0}catch{return!1}finally{await y(o,{force:!0}).catch(()=>{})}}const K=4,kt="grix-wrapper-template:";function Ct(t){const r=c.join(t.rootDir,"data","upgrade-wrapper-child.json"),e=[`"${t.cliPath}"`,...t.configDir?["--config-dir",`"${t.configDir}"`]:[]],n=["$ErrorActionPreference = 'Stop'",`$recordPath = ${A(r)}`,"$exitCode = 1","try {"," [IO.Directory]::CreateDirectory([IO.Path]::GetDirectoryName($recordPath)) | Out-Null",` $p = Start-Process -FilePath ${A(t.nodePath)} -ArgumentList @(${e.map(A).join(", ")}) -WindowStyle Hidden -PassThru`,` $record = @{ pid = $p.Id; launched_at = [DateTimeOffset]::UtcNow.ToUnixTimeMilliseconds(); boot_time = [DateTimeOffset]::UtcNow.ToUnixTimeMilliseconds() - [Environment]::TickCount64; cli_path = ${A(t.cliPath)} }`," $utf8NoBom = New-Object System.Text.UTF8Encoding($false)"," try {"," [IO.File]::WriteAllText($recordPath, ($record | ConvertTo-Json -Compress), $utf8NoBom)"," } catch {",' & "$env:SystemRoot\\System32\\taskkill.exe" /PID $p.Id /T /F 2>$null | Out-Null'," $p.WaitForExit()"," throw"," }"," $p.WaitForExit()"," $exitCode = $p.ExitCode","} finally {"," Remove-Item -LiteralPath $recordPath -Force -ErrorAction SilentlyContinue","}","exit $exitCode"].join(`
|
|
100
|
+
`),i=Buffer.from(n,"utf16le").toString("base64"),l=`"${c.join(process.env.SystemRoot||"C:\\Windows","System32","WindowsPowerShell","v1.0","powershell.exe")}" -NoProfile -NonInteractive -ExecutionPolicy Bypass -EncodedCommand ${i}`,a=c.join(t.rootDir,"bin","upgrade-guardian.mjs"),s=c.join(t.rootDir,"bin","upgrade-guardian.fallback.mjs"),u=c.join(t.rootDir,"data","upgrade-wrapper.pause.json"),d=c.join(t.rootDir,"data","upgrade-pending.json"),h=c.join(t.rootDir,"data"),g=c.join(h,"wrapper.lock"),E=[`"${m(t.nodePath)}"`,`"${m(a)}"`,"activate","--root",`"${m(t.rootDir)}"`].join(" "),F=`${E} --wrapper-handoff`,H=[`"${m(t.nodePath)}"`,`"${m(s)}"`,"activate","--root",`"${m(t.rootDir)}"`].join(" "),et=`${H} --wrapper-handoff`;return[`' ${kt} ${K}`,"Option Explicit","Dim shell, processEnv, fso, command, guardianCommand, handoffGuardianCommand, guardianFallbackCommand, handoffGuardianFallbackCommand, guardianPath, guardianFallbackPath, maintenanceFile, pendingFile, delayMs, rapidCount, guardianExit, wrapperLockDir, wrapperLockFile, wrapperLock",`command = "${m(l)}"`,`guardianCommand = "${m(E)}"`,`handoffGuardianCommand = "${m(F)}"`,`guardianFallbackCommand = "${m(H)}"`,`handoffGuardianFallbackCommand = "${m(et)}"`,`guardianPath = "${m(a)}"`,`guardianFallbackPath = "${m(s)}"`,`maintenanceFile = "${m(u)}"`,`pendingFile = "${m(d)}"`,`wrapperLockDir = "${m(h)}"`,`wrapperLockFile = "${m(g)}"`,'Set shell = CreateObject("WScript.Shell")','Set processEnv = shell.Environment("Process")','Set fso = CreateObject("Scripting.FileSystemObject")',"On Error Resume Next","If Not fso.FolderExists(wrapperLockDir) Then fso.CreateFolder wrapperLockDir","Err.Clear","Set wrapperLock = fso.OpenTextFile(wrapperLockFile, 2, True)","If Err.Number <> 0 Then"," Err.Clear"," If fso.FileExists(wrapperLockFile) Then"," On Error GoTo 0"," WScript.Quit 0"," End If","Else"," wrapperLock.Write CStr(Now())"," Err.Clear","End If","On Error GoTo 0",`processEnv("${T}") = "${m(t.rootDir)}"`,'processEnv("GRIX_WRAPPER_SUPERVISED") = "1"',...j().map(([rt,nt])=>`processEnv("${rt}") = "${nt}"`),"delayMs = 5000","rapidCount = 0","Do"," Do While fso.FileExists(maintenanceFile)"," If fso.FileExists(guardianPath) Then"," guardianExit = shell.Run(guardianCommand, 0, True)"," ElseIf fso.FileExists(guardianFallbackPath) Then"," guardianExit = shell.Run(guardianFallbackCommand, 0, True)"," Else"," On Error Resume Next"," fso.DeleteFile maintenanceFile, True"," On Error GoTo 0"," WScript.Sleep 1000"," End If"," If fso.FileExists(maintenanceFile) Then WScript.Sleep 3000"," Loop"," If fso.FileExists(pendingFile) Then"," If fso.FileExists(guardianPath) Then"," guardianExit = shell.Run(guardianCommand, 0, True)"," ElseIf fso.FileExists(guardianFallbackPath) Then"," guardianExit = shell.Run(guardianFallbackCommand, 0, True)"," End If"," End If"," shell.Run command, 0, True"," If fso.FileExists(pendingFile) Then"," If fso.FileExists(guardianPath) Then"," guardianExit = shell.Run(handoffGuardianCommand, 0, True)"," ElseIf fso.FileExists(guardianFallbackPath) Then"," guardianExit = shell.Run(handoffGuardianFallbackCommand, 0, True)"," End If"," End If"," If fso.FileExists(pendingFile) And Not PendingIsTerminal() Then"," rapidCount = 0"," WScript.Sleep delayMs"," ElseIf fso.FileExists(maintenanceFile) Then"," rapidCount = 0"," Else"," rapidCount = rapidCount + 1"," If rapidCount >= 10 Then"," WScript.Sleep 300000"," rapidCount = 0"," Else"," WScript.Sleep delayMs"," End If"," End If","Loop","","Function PendingIsTerminal()"," Dim stream, text"," PendingIsTerminal = False"," On Error Resume Next"," Set stream = fso.OpenTextFile(pendingFile, 1)"," If Err.Number <> 0 Then"," Err.Clear"," On Error GoTo 0"," Exit Function"," End If"," text = stream.ReadAll"," stream.Close"," If Err.Number <> 0 Then"," Err.Clear"," On Error GoTo 0"," Exit Function"," End If"," On Error GoTo 0",' text = Replace(Replace(Replace(text, " ", ""), vbCr, ""), vbLf, "")',' If InStr(text, """phase"":""failed""") > 0 Then PendingIsTerminal = True',' If InStr(text, """phase"":""finalizing""") > 0 Then PendingIsTerminal = True',"End Function",""].join(`\r
|
|
101
|
+
`)}function vt(t,r){return c.join(ht(t,r),"dist","service","platform-adapter.js")}async function Tt(t,r={}){const e={version:K,build:Ct};try{if(c.basename(t)!==pt)return e;const n=c.dirname(t),i=ft(n,"current");if(!i)return e;const o=vt(n,i),l=r.selfModulePath??ot(import.meta.url);if(c.resolve(o)===c.resolve(l)||!v(o))return e;const a=await import(at(o).href),s=Number(a.WINDOWS_WRAPPER_TEMPLATE_VERSION),u=a.buildWindowsWrapperScript;return typeof u!="function"||!Number.isFinite(s)||s<=e.version?e:{version:s,build:u}}catch{return e}}function b(t){return`gui/${t??0}`}function bt(t=process.env){return t.GRIX_LAUNCHER_MANAGED==="1"||!!t.GRIX_CLAUDE_INTERNAL_API_URL}function U(t){const r=String(t?.stdout??"").trim();return String(t?.stderr??"").trim()||r||`exit=${Number(t?.exitCode??-1)}`}function N(t,r,e,n){if(t?.trim())return c.resolve(t);const i=r||e;return i?c.resolve(c.dirname(c.dirname(i))):c.join(n,".grix")}async function q(t){try{await it(t)}catch{throw new Error(`launchd plist missing: ${t}`)}}async function Y(t){const{serviceID:r,domain:e,runCommand:n}=t,i=`${e}/${r}`,o=await n("launchctl",["bootout",i],{allowFailure:!0});if(Number(o?.exitCode??-1)!==0){const l=await n("launchctl",["print",i],{allowFailure:!0});if(Number(l?.exitCode??1)===0){await new Promise(s=>setTimeout(s,250));const a=await n("launchctl",["print",i],{allowFailure:!0});if(Number(a?.exitCode??1)===0)throw new Error(`launchctl bootout ${i}: ${U(o)}`)}return}for(let l=0;l<20;l+=1){const a=await n("launchctl",["print",i],{allowFailure:!0});if(Number(a?.exitCode??1)!==0)return;await new Promise(s=>setTimeout(s,250))}throw new Error(`launchctl bootout ${i}: service remains loaded`)}async function B(t){const{serviceID:r,domain:e,definitionPath:n,runCommand:i}=t,o=`${e}/${r}`,l=await i("launchctl",["bootstrap",e,n],{allowFailure:!0});if(Number(l?.exitCode??-1)===0)return;const a=await i("launchctl",["print",o],{allowFailure:!0});Number(a?.exitCode??1)===0&&await Y(t);const s=await i("launchctl",["bootstrap",e,n],{allowFailure:!0});if(Number(s?.exitCode??-1)!==0)throw new Error(`launchctl bootstrap ${e} failed: initial=${U(l)}; retry=${U(s)}`)}function Ft(){return{platform:"darwin",kind:"launchd",async install({serviceID:t,nodePath:r,cliPath:e,configDir:n,rootDir:i,stdoutPath:o,stderrPath:l,environmentPath:a="",homeDir:s=p.homedir()}){const u=mt(t,s),d=N(i,o,l,s);return await P(c.dirname(u),{recursive:!0}),await $(u,wt({serviceID:t,nodePath:r,cliPath:e,configDir:n,rootDir:d,stdoutPath:o,stderrPath:l,environmentPath:a}),{encoding:"utf8",mode:384}),{definitionPath:u}},async start({serviceID:t,definitionPath:r,runCommand:e=f,uid:n=process.getuid?.()??0}){const i=b(n);await q(r),await B({serviceID:t,domain:i,definitionPath:r,runCommand:e})},async stop({serviceID:t,runCommand:r=f,uid:e=process.getuid?.()??0}){const n=b(e);await r("launchctl",["bootout",`${n}/${t}`],{allowFailure:!0})},async restart({serviceID:t,definitionPath:r,runCommand:e=f,uid:n=process.getuid?.()??0,env:i=process.env,reloadDefinition:o=!1}){const l=b(n),a={serviceID:t,domain:l,definitionPath:r,runCommand:e};if(await q(r),!o&&bt(i)){const s=await e("launchctl",["kickstart","-k",`${l}/${t}`],{allowFailure:!0});if(Number(s?.exitCode??-1)===0)return;await B(a);return}await Y(a),await B(a)},async uninstall({serviceID:t,definitionPath:r,runCommand:e=f,uid:n=process.getuid?.()??0}){const i=b(n);await e("launchctl",["bootout",`${i}/${t}`],{allowFailure:!0}),await y(r,{force:!0})},async discoverServices({homeDir:t=p.homedir()}={}){const r=c.join(t,"Library","LaunchAgents"),e=await I(r).catch(()=>[]),n=L("darwin"),i=[];for(const o of e){if(!o.startsWith(n)||!o.endsWith(".plist"))continue;const l=o.slice(0,-6),a=c.join(r,o);let s=null;try{const u=await S(a,"utf8");s=lt(u)}catch{}i.push({serviceID:l,definitionPath:a,configDir:s})}return i},async isServiceLoaded({serviceID:t,runCommand:r=f,uid:e=process.getuid?.()??0}){const n=b(e),i=await r("launchctl",["print",`${n}/${t}`],{allowFailure:!0});return Number(i?.exitCode??1)===0}}}function It(t){return`${t}-wrapper.vbs`}const Rt=5e3;async function G(t,r){const e=await ct(It(t),{runCommandImpl:r,platform:"win32"}).catch(()=>[]),n=new Set([process.pid,process.ppid]);return e.filter(i=>!n.has(i))}async function Lt(t,r,e=Rt){const n=Date.now()+e;let i=await G(t,r);for(;i.length>0&&Date.now()<n;)await new Promise(o=>setTimeout(o,250)),i=await G(t,r);return i}function Dt(){return{platform:"win32",kind:"task-scheduler",async install({serviceID:t,nodePath:r,cliPath:e,configDir:n,rootDir:i,stdoutPath:o,stderrPath:l,runCommand:a=f,homeDir:s=p.homedir()}){const u=k(t,s),d=N(i,o,l,s);await P(c.dirname(u),{recursive:!0});const h=await Tt(e);await $(u,h.build({nodePath:r,cliPath:e,configDir:n,rootDir:d}),"utf8");let g=!1;st()&&(g=await xt({serviceID:t,wrapperPath:u,runCommand:a}));const E=M(t,s);return g?await y(E,{force:!0}).catch(()=>{}):await Et({wrapperPath:u,shortcutPath:E,runCommand:a}),{definitionPath:g?`task:${t}`:`startup:${t}`}},async start({serviceID:t,definitionPath:r,runCommand:e=f,homeDir:n=p.homedir()}){const i=k(t,n);if(r.startsWith("task:"))try{await e("schtasks",["/Run","/TN",t]);return}catch{}(await G(t,e)).length>0||_("wscript.exe",["//B","//NoLogo",i])},async stop({serviceID:t,runCommand:r=f,homeDir:e=p.homedir()}){await r("schtasks",["/End","/TN",t],{allowFailure:!0});const n=`${t}-wrapper.vbs`;await X(n,{platform:"win32"})},async restart({serviceID:t,definitionPath:r,runCommand:e=f,homeDir:n=p.homedir()}){await e("schtasks",["/End","/TN",t],{allowFailure:!0});const i=`${t}-wrapper.vbs`;await X(i,{platform:"win32"});const o=k(t,n);if(r?.startsWith("task:"))try{await e("schtasks",["/Run","/TN",t]);return}catch{}(await Lt(t,e)).length>0||_("wscript.exe",["//B","//NoLogo",o])},async uninstall({serviceID:t,runCommand:r=f,homeDir:e=p.homedir()}){await r("schtasks",["/Delete","/TN",t,"/F"],{allowFailure:!0});const n=k(t,e);await y(n,{force:!0});const i=M(t,e);await y(i,{force:!0})},async discoverServices({homeDir:t=p.homedir(),runCommand:r=f}={}){const e=L("win32"),n=await r("schtasks",["/Query","/FO","CSV","/NH"],{allowFailure:!0}),i=[];if(Number(n?.exitCode??-1)===0){const a=String(n.stdout??"").split(/\r?\n/);for(const s of a){const u=s.match(/^"([^"]+)"/);if(!u)continue;const d=u[1];if(!d.startsWith(e))continue;let h=null;try{const g=k(d,t),F=(await S(g,"utf8")).match(/--config-dir\s+""([^""]+)""/);F&&(h=F[1])}catch{}i.push({serviceID:d,definitionPath:`task:${d}`,configDir:h})}}const o=c.join(t,"AppData","Roaming","Microsoft","Windows","Start Menu","Programs","Startup"),l=await I(o).catch(()=>[]);for(const a of l){if(!a.startsWith(e)||!a.endsWith(".lnk"))continue;const s=a.slice(0,-4);if(i.some(d=>d.serviceID===s))continue;let u=null;try{const d=k(s,t),g=(await S(d,"utf8")).match(/--config-dir\s+""([^""]+)""/);g&&(u=g[1])}catch{}i.push({serviceID:s,definitionPath:`startup:${s}`,configDir:u})}return i},async isServiceLoaded({serviceID:t,runCommand:r=f,homeDir:e=p.homedir()}){const n=await r("schtasks",["/Query","/TN",t,"/NH"],{allowFailure:!0});return Number(n?.exitCode??1)===0?!0:v(M(t,e))}}}function At(){return{platform:"linux",kind:"systemd-user",async install({serviceID:t,nodePath:r,cliPath:e,configDir:n,rootDir:i,stdoutPath:o,stderrPath:l,environmentPath:a="",homeDir:s=p.homedir(),runCommand:u=f}){const d=dt(t,s),h=N(i,o,l,s);return await P(c.dirname(d),{recursive:!0}),await $(d,yt({serviceID:t,nodePath:r,cliPath:e,configDir:n,rootDir:h,stdoutPath:o,stderrPath:l,environmentPath:a}),{encoding:"utf8",mode:384}),await u("systemctl",["--user","daemon-reload"]),await u("systemctl",["--user","enable",`${t}.service`]),{definitionPath:d}},async start({serviceID:t,runCommand:r=f}){await r("systemctl",["--user","start",`${t}.service`])},async stop({serviceID:t,runCommand:r=f}){await r("systemctl",["--user","stop",`${t}.service`],{allowFailure:!0})},async restart({serviceID:t,runCommand:r=f}){await r("systemctl",["--user","restart",`${t}.service`])},async uninstall({serviceID:t,definitionPath:r,runCommand:e=f}){await e("systemctl",["--user","stop",`${t}.service`],{allowFailure:!0}),await e("systemctl",["--user","disable",`${t}.service`],{allowFailure:!0}),await y(r,{force:!0}),await e("systemctl",["--user","daemon-reload"])},async discoverServices({homeDir:t=p.homedir()}={}){const r=c.join(t,".config","systemd","user"),e=await I(r).catch(()=>[]),n=L("linux"),i=[];for(const o of e){if(!o.startsWith(n)||!o.endsWith(".service"))continue;const l=o.slice(0,-8),a=c.join(r,o);let s=null;try{const u=await S(a,"utf8");s=ut(u)}catch{}i.push({serviceID:l,definitionPath:a,configDir:s})}return i},async isServiceLoaded({serviceID:t,runCommand:r=f}){const e=await r("systemctl",["--user","is-active",`${t}.service`],{allowFailure:!0});return String(e?.stdout??"").trim()==="active"}}}function C(t){try{const r=V(t,"utf8"),e=JSON.parse(r);if(e&&typeof e.service_id=="string"&&typeof e.node_path=="string"&&typeof e.cli_path=="string"&&typeof e.root_dir=="string")return e}catch{}return null}function Nt(t){return c.join(t,"daemon.lock.json")}function W(t){const r=Nt(t);try{const e=V(r,"utf8"),n=JSON.parse(e);if(typeof n?.pid=="number")return n.pid}catch{}return 0}function Z(t){return c.join(t,".profile")}function Wt(t){return t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function _t(t){const r=[D(t.nodePath),D(t.cliPath)];t.configDir&&r.push("--config-dir",D(t.configDir));const e=`env ${T}=${D(t.rootDir)} ${r.join(" ")}`;return`${e} status >/dev/null 2>&1 || (nohup ${e} start >/dev/null 2>&1 &)`}function Ot(t,r){return`# >>> grix-connector autostart [${t}] >>>
|
|
102
|
+
${r}
|
|
103
103
|
# <<< grix-connector autostart [${t}] <<<
|
|
104
|
-
`}function tt(t){const
|
|
105
|
-
${i}`).replace(/^\n+/,"");else{const a=
|
|
104
|
+
`}function tt(t){const r=Wt(t);return new RegExp(`(?:^|\\n)# >>> grix-connector autostart \\[${r}\\] >>>\\n[\\s\\S]*?\\n# <<< grix-connector autostart \\[${r}\\] <<<\\n?`,"m")}async function jt(t,r,e){let n="";try{n=await S(t,"utf8")}catch{}const i=Ot(r,e),o=tt(r);let l;if(o.test(n))l=n.replace(o,`
|
|
105
|
+
${i}`).replace(/^\n+/,"");else{const a=n.length===0||n.endsWith(`
|
|
106
106
|
`)?"":`
|
|
107
|
-
`;l=`${
|
|
108
|
-
`,{encoding:"utf8",mode:384});const h=_t({nodePath:
|
|
107
|
+
`;l=`${n}${a}${i}`}l!==n&&(await P(c.dirname(t),{recursive:!0}),await $(t,l,{encoding:"utf8"}))}async function Mt(t,r){let e="";try{e=await S(t,"utf8")}catch{return}const n=tt(r);if(!n.test(e))return;const i=e.replace(n,"").replace(/^\n+/,"");await $(t,i,{encoding:"utf8"})}function Ut(){return{platform:"linux",kind:"bare-daemon",async install({serviceID:t,nodePath:r,cliPath:e,configDir:n,rootDir:i,stdoutPath:o,stderrPath:l,homeDir:a=p.homedir()}){const s=x(t,a);await P(c.dirname(s),{recursive:!0});const u=N(i,o,l,a),d={schema_version:1,service_id:t,node_path:r,cli_path:e,config_dir:n??"",root_dir:u,stdout_path:o,stderr_path:l,installed_at:Date.now()};await $(s,`${JSON.stringify(d,null,2)}
|
|
108
|
+
`,{encoding:"utf8",mode:384});const h=_t({nodePath:r,cliPath:e,configDir:n??"",rootDir:u});return await jt(Z(a),t,h),{definitionPath:s}},async start({serviceID:t,homeDir:r=p.homedir()}){const e=x(t,r),n=C(e);if(!n)throw new Error(`bare-daemon marker missing: ${e}`);const i=[n.cli_path];n.config_dir&&i.push("--config-dir",n.config_dir),_(n.node_path,i,{env:{...process.env,[T]:n.root_dir}})},async stop({serviceID:t,homeDir:r=p.homedir()}){const e=x(t,r),n=C(e);if(!n)return;const i=W(n.root_dir);if(i>0&&R(i))try{process.kill(i,"SIGTERM")}catch{}},async restart(t){await this.stop(t);const r=Date.now()+5e3,e=x(t.serviceID,t.homeDir??p.homedir()),n=C(e);for(;n&&Date.now()<r;){const i=W(n.root_dir);if(i<=0||!R(i))break;await new Promise(o=>setTimeout(o,100))}await this.start(t)},async uninstall({serviceID:t,homeDir:r=p.homedir()}){const e=x(t,r),n=C(e);if(n){const i=W(n.root_dir);if(i>0&&R(i))try{process.kill(i,"SIGTERM")}catch{}}await y(e,{force:!0}),await Mt(Z(r),t)},async discoverServices({homeDir:t=p.homedir()}={}){const r=c.join(t,".grix","service"),e=await I(r).catch(()=>[]),n=L("linux"),i=[];for(const o of e){if(!o.startsWith(n)||!o.endsWith(".bare.json"))continue;const l=o.slice(0,-10),a=c.join(r,o),s=C(a);i.push({serviceID:l,definitionPath:a,configDir:s?.config_dir||null})}return i},async isServiceLoaded({serviceID:t,homeDir:r=p.homedir()}){const e=x(t,r),n=C(e);if(!n)return!1;const i=W(n.root_dir);return i>0&&R(i)}}}function Bt(t=process.getuid?.()??0){if(process.env.GRIX_FORCE_BARE_DAEMON==="1")return!1;const r=process.env.XDG_RUNTIME_DIR;return!!(r&&v(c.join(r,"bus"))||v(`/run/user/${t}/bus`))}function Yt(t=process.platform,r={}){return t==="darwin"?Ft():t==="win32"?Dt():r.systemdUserAvailable??Bt()?At():Ut()}export{kt as WINDOWS_WRAPPER_TEMPLATE_MARKER,K as WINDOWS_WRAPPER_TEMPLATE_VERSION,Ct as buildWindowsWrapperScript,j as collectServicePortEnv,Yt as getPlatformServiceAdapter,bt as isInsideManagedDaemonTree,Bt as isSystemdUserBusAvailable,Mt as removeProfileAutostart,M as resolveWindowsStartupShortcutPath,k as resolveWindowsWrapperPath,Tt as resolveWindowsWrapperTemplateSource,jt as upsertProfileAutostart};
|