grix-connector 4.6.6 → 4.6.8
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.
|
Binary file
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
|
-
"bridgeVersion": "4.6.
|
|
4
|
-
"tarball": "grix-dsh-bridge-4.6.
|
|
5
|
-
"size":
|
|
3
|
+
"bridgeVersion": "4.6.8",
|
|
4
|
+
"tarball": "grix-dsh-bridge-4.6.8.tgz",
|
|
5
|
+
"size": 23091,
|
|
6
6
|
"unpackedSize": 92668,
|
|
7
|
-
"shasum": "
|
|
8
|
-
"integrity": "sha512-
|
|
7
|
+
"shasum": "c297cfaad8d1a80b7104bc3b14dc8605b7165441",
|
|
8
|
+
"integrity": "sha512-ZHI0NOgBjocDW9/eetqCO0csfdH+vrFbD4EwgtVLC0LHUeb3RRJdsAC/TrEZ3F2NIvr+73AWAP705ydg/zzWrQ=="
|
|
9
9
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
function a(
|
|
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,4 +1,4 @@
|
|
|
1
|
-
import{existsSync as b,readFileSync as U}from"node:fs";import{mkdir as k,readdir as F,readFile as
|
|
1
|
+
import{existsSync as b,readFileSync as U}from"node:fs";import{mkdir as k,readdir as F,readFile as P,rm as y,stat as tt,writeFile as $}from"node:fs/promises";import m from"node:os";import c from"node:path";import{GRIX_HOME_ENV as v}from"../core/config/paths.js";import{isProcessRunning as I,runCommand as f,spawnDetached as L,isWindowsElevated as et,killProcessesByCommandLine as G}from"./process-control.js";import{getServicePrefix as D,parseConfigDirFromPlistXML as nt,parseConfigDirFromSystemdUnit as rt,resolveBareDaemonMarkerPath as S,resolveLinuxUserUnitPath as it,resolveMacOSLaunchAgentPath as ot}from"./service-paths.js";function g(t){return String(t??"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}function R(t){return`'${String(t??"").replace(/'/g,"'\\''")}'`}function H(t){return String(t??"").replace(/\\/g,"\\\\").replace(/"/g,'\\"').replace(/\n/g,"\\n").replace(/\r/g,"\\r")}function V(t){return`"${H(t).replace(/%/g,"%%")}"`}function _(t){return String(t??"").replace(/%/g,"%%")}function at(t){return`"${H(t).replace(/\$/g,()=>"$$").replace(/%/g,"%%")}"`}function j(t=process.env){const e=[];for(const n of["GRIX_HEALTH_PORT","GRIX_ADMIN_PORT"]){const r=String(t[n]??"").trim();/^\d{2,5}$/.test(r)&&e.push([n,r])}return e}function X(t){return[t.nodePath,t.cliPath,...t.configDir?["--config-dir",t.configDir]:[]]}function st(t){const e=X(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>
|
|
@@ -20,7 +20,7 @@ ${e.map(n=>` <string>${g(n)}</string>`).join(`
|
|
|
20
20
|
<string>${g(c.dirname(t.cliPath))}</string>
|
|
21
21
|
<key>EnvironmentVariables</key>
|
|
22
22
|
<dict>
|
|
23
|
-
<key>${
|
|
23
|
+
<key>${v}</key>
|
|
24
24
|
<string>${g(t.rootDir)}</string>
|
|
25
25
|
${j().map(([n,r])=>` <key>${n}</key>
|
|
26
26
|
<string>${r}</string>
|
|
@@ -33,26 +33,27 @@ ${j().map(([n,r])=>` <key>${n}</key>
|
|
|
33
33
|
<string>${g(t.stderrPath)}</string>
|
|
34
34
|
</dict>
|
|
35
35
|
</plist>
|
|
36
|
-
`}function
|
|
36
|
+
`}function ct(t){const e=X(t).map(n=>at(n)).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
42
|
ExecStart=${e}
|
|
43
|
-
WorkingDirectory=${
|
|
44
|
-
Environment=${
|
|
43
|
+
WorkingDirectory=${_(c.dirname(t.cliPath))}
|
|
44
|
+
Environment=${V(`${v}=${t.rootDir}`)}
|
|
45
45
|
${j().map(([n,r])=>`Environment=${n}=${r}
|
|
46
|
-
`).join("")}
|
|
46
|
+
`).join("")}${t.environmentPath?`Environment=${V(`PATH=${t.environmentPath}`)}
|
|
47
|
+
`:""}
|
|
47
48
|
Restart=always
|
|
48
49
|
RestartSec=30
|
|
49
|
-
StandardOutput
|
|
50
|
-
StandardError
|
|
50
|
+
StandardOutput=append:${_(t.stdoutPath)}
|
|
51
|
+
StandardError=append:${_(t.stderrPath)}
|
|
51
52
|
|
|
52
53
|
[Install]
|
|
53
54
|
WantedBy=default.target
|
|
54
|
-
`}function
|
|
55
|
-
`);return{path:n,content:r}}async function
|
|
55
|
+
`}function x(t,e){const n=t.replace(/[^a-zA-Z0-9._-]/g,"_");return c.join(e,".grix",`${n}-wrapper.vbs`)}function M(t,e){const n=t.replace(/[^a-zA-Z0-9._-]/g,"_"),r=c.join(e,"AppData","Roaming","Microsoft","Windows","Start Menu","Programs","Startup");return c.join(r,`${n}.lnk`)}function h(t){return String(t??"").replace(/"/g,'""')}function A(t){return`'${String(t??"").replace(/'/g,"''")}'`}function lt(t,e){const n=c.join(c.dirname(t),c.basename(e).replace(/\.lnk$/,"-create.vbs")),r=["Option Explicit","Dim shell, shortcut",'Set shell = CreateObject("WScript.Shell")',`Set shortcut = shell.CreateShortcut("${h(e)}")`,'shortcut.TargetPath = "wscript.exe"',`shortcut.Arguments = "//B //NoLogo \\"${h(t)}\\""`,"shortcut.WindowStyle = 7","shortcut.Save",""].join(`\r
|
|
56
|
+
`);return{path:n,content:r}}async function ut(t){const{wrapperPath:e,shortcutPath:n,runCommand:r}=t,i=lt(e,n);for(let o=1;o<=3;o+=1){try{await $(i.path,i.content,"utf8"),await r("wscript.exe",[i.path,"//B","//NoLogo"])}catch{}finally{await y(i.path,{force:!0}).catch(()=>{})}if(b(n))return!0}return console.warn(`Warning: failed to create Windows logon-autostart shortcut at ${n}. The daemon will NOT start automatically after the next reboot/logon. Check Controlled Folder Access / antivirus blocking writes to the Startup folder, or create the shortcut manually.`),!1}async function dt(t){try{const e=await t("whoami",["/user","/fo","csv","/nh"],{allowFailure:!0}),n=String(e?.stdout??"").match(/"(S-1-[0-9-]+)"/);if(n)return n[1]}catch{}return null}function mt(t){const e=`//B //NoLogo "${t.wrapperPath}"`;return`<?xml version="1.0" encoding="UTF-16"?>
|
|
56
57
|
<Task version="1.2" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
|
|
57
58
|
<RegistrationInfo>
|
|
58
59
|
<Description>grix-connector daemon autostart</Description>
|
|
@@ -95,13 +96,13 @@ WantedBy=default.target
|
|
|
95
96
|
</Exec>
|
|
96
97
|
</Actions>
|
|
97
98
|
</Task>
|
|
98
|
-
`}async function
|
|
99
|
-
`),i=Buffer.from(r,"utf16le").toString("base64"),l=`"${c.join(process.env.SystemRoot||"C:\\Windows","System32","WindowsPowerShell","v1.0","powershell.exe")}" -NoProfile -NonInteractive -ExecutionPolicy Bypass -EncodedCommand ${i}`,
|
|
100
|
-
`)}function
|
|
99
|
+
`}async function ft(t){const{serviceID:e,wrapperPath:n,runCommand:r}=t,i=await dt(r)??m.userInfo().username,o=c.join(c.dirname(n),`${e}-task.xml`);try{const a=mt({userId:i,wrapperPath:n});return await $(o,"\uFEFF"+a,"utf16le"),await r("schtasks",["/Create","/TN",e,"/XML",o,"/F"]),!0}catch{return!1}finally{await y(o,{force:!0}).catch(()=>{})}}const ht=3,pt="grix-wrapper-template:";function gt(t){const e=c.join(t.rootDir,"data","upgrade-wrapper-child.json"),n=[`"${t.cliPath}"`,...t.configDir?["--config-dir",`"${t.configDir}"`]:[]],r=["$ErrorActionPreference = 'Stop'",`$recordPath = ${A(e)}`,"$exitCode = 1","try {"," [IO.Directory]::CreateDirectory([IO.Path]::GetDirectoryName($recordPath)) | Out-Null",` $p = Start-Process -FilePath ${A(t.nodePath)} -ArgumentList @(${n.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(r,"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"),p=[`"${h(t.nodePath)}"`,`"${h(a)}"`,"activate","--root",`"${h(t.rootDir)}"`].join(" "),w=`${p} --wrapper-handoff`,O=[`"${h(t.nodePath)}"`,`"${h(s)}"`,"activate","--root",`"${h(t.rootDir)}"`].join(" "),T=`${O} --wrapper-handoff`;return[`' ${pt} ${ht}`,"Option Explicit","Dim shell, processEnv, fso, command, guardianCommand, handoffGuardianCommand, guardianFallbackCommand, handoffGuardianFallbackCommand, guardianPath, guardianFallbackPath, maintenanceFile, pendingFile, delayMs, rapidCount, guardianExit",`command = "${h(l)}"`,`guardianCommand = "${h(p)}"`,`handoffGuardianCommand = "${h(w)}"`,`guardianFallbackCommand = "${h(O)}"`,`handoffGuardianFallbackCommand = "${h(T)}"`,`guardianPath = "${h(a)}"`,`guardianFallbackPath = "${h(s)}"`,`maintenanceFile = "${h(u)}"`,`pendingFile = "${h(d)}"`,'Set shell = CreateObject("WScript.Shell")','Set processEnv = shell.Environment("Process")','Set fso = CreateObject("Scripting.FileSystemObject")',`processEnv("${v}") = "${h(t.rootDir)}"`,'processEnv("GRIX_WRAPPER_SUPERVISED") = "1"',...j().map(([Z,Y])=>`processEnv("${Z}") = "${Y}"`),"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 C(t){return`gui/${t??0}`}function B(t){const e=String(t?.stdout??"").trim();return String(t?.stderr??"").trim()||e||`exit=${Number(t?.exitCode??-1)}`}function N(t,e,n,r){if(t?.trim())return c.resolve(t);const i=e||n;return i?c.resolve(c.dirname(c.dirname(i))):c.join(r,".grix")}async function Q(t){try{await tt(t)}catch{throw new Error(`launchd plist missing: ${t}`)}}async function z(t){const{serviceID:e,domain:n,runCommand:r}=t,i=`${n}/${e}`,o=await r("launchctl",["bootout",i],{allowFailure:!0});if(Number(o?.exitCode??-1)!==0){const l=await r("launchctl",["print",i],{allowFailure:!0});if(Number(l?.exitCode??1)===0){await new Promise(s=>setTimeout(s,250));const a=await r("launchctl",["print",i],{allowFailure:!0});if(Number(a?.exitCode??1)===0)throw new Error(`launchctl bootout ${i}: ${B(o)}`)}return}for(let l=0;l<20;l+=1){const a=await r("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 J(t){const{serviceID:e,domain:n,definitionPath:r,runCommand:i}=t,o=`${n}/${e}`,l=await i("launchctl",["bootstrap",n,r],{allowFailure:!0});if(Number(l?.exitCode??-1)===0)return;const a=await i("launchctl",["print",o],{allowFailure:!0});Number(a?.exitCode??1)===0&&await z(t);const s=await i("launchctl",["bootstrap",n,r],{allowFailure:!0});if(Number(s?.exitCode??-1)!==0)throw new Error(`launchctl bootstrap ${n} failed: initial=${B(l)}; retry=${B(s)}`)}function wt(){return{platform:"darwin",kind:"launchd",async install({serviceID:t,nodePath:e,cliPath:n,configDir:r,rootDir:i,stdoutPath:o,stderrPath:l,environmentPath:a="",homeDir:s=m.homedir()}){const u=ot(t,s),d=N(i,o,l,s);return await k(c.dirname(u),{recursive:!0}),await $(u,st({serviceID:t,nodePath:e,cliPath:n,configDir:r,rootDir:d,stdoutPath:o,stderrPath:l,environmentPath:a}),{encoding:"utf8",mode:384}),{definitionPath:u}},async start({serviceID:t,definitionPath:e,runCommand:n=f,uid:r=process.getuid?.()??0}){const i=C(r);await Q(e),await J({serviceID:t,domain:i,definitionPath:e,runCommand:n})},async stop({serviceID:t,runCommand:e=f,uid:n=process.getuid?.()??0}){const r=C(n);await e("launchctl",["bootout",`${r}/${t}`],{allowFailure:!0})},async restart({serviceID:t,definitionPath:e,runCommand:n=f,uid:r=process.getuid?.()??0}){const i=C(r),o={serviceID:t,domain:i,definitionPath:e,runCommand:n};await Q(e),await z(o),await J(o)},async uninstall({serviceID:t,definitionPath:e,runCommand:n=f,uid:r=process.getuid?.()??0}){const i=C(r);await n("launchctl",["bootout",`${i}/${t}`],{allowFailure:!0}),await y(e,{force:!0})},async discoverServices({homeDir:t=m.homedir()}={}){const e=c.join(t,"Library","LaunchAgents"),n=await F(e).catch(()=>[]),r=D("darwin"),i=[];for(const o of n){if(!o.startsWith(r)||!o.endsWith(".plist"))continue;const l=o.slice(0,-6),a=c.join(e,o);let s=null;try{const u=await P(a,"utf8");s=nt(u)}catch{}i.push({serviceID:l,definitionPath:a,configDir:s})}return i},async isServiceLoaded({serviceID:t,runCommand:e=f,uid:n=process.getuid?.()??0}){const r=C(n),i=await e("launchctl",["print",`${r}/${t}`],{allowFailure:!0});return Number(i?.exitCode??1)===0}}}function yt(){return{platform:"win32",kind:"task-scheduler",async install({serviceID:t,nodePath:e,cliPath:n,configDir:r,rootDir:i,stdoutPath:o,stderrPath:l,runCommand:a=f,homeDir:s=m.homedir()}){const u=x(t,s),d=N(i,o,l,s);await k(c.dirname(u),{recursive:!0}),await $(u,gt({nodePath:e,cliPath:n,configDir:r,rootDir:d}),"utf8");let p=!1;et()&&(p=await ft({serviceID:t,wrapperPath:u,runCommand:a}));const w=M(t,s);return p?await y(w,{force:!0}).catch(()=>{}):await ut({wrapperPath:u,shortcutPath:w,runCommand:a}),{definitionPath:p?`task:${t}`:`startup:${t}`}},async start({serviceID:t,definitionPath:e,runCommand:n=f,homeDir:r=m.homedir()}){const i=x(t,r);if(e.startsWith("task:"))try{await n("schtasks",["/Run","/TN",t]);return}catch{}L("wscript.exe",["//B","//NoLogo",i])},async stop({serviceID:t,runCommand:e=f,homeDir:n=m.homedir()}){await e("schtasks",["/End","/TN",t],{allowFailure:!0});const r=`${t}-wrapper.vbs`;await G(r,{platform:"win32"})},async restart({serviceID:t,definitionPath:e,runCommand:n=f,homeDir:r=m.homedir()}){await n("schtasks",["/End","/TN",t],{allowFailure:!0});const i=`${t}-wrapper.vbs`;await G(i,{platform:"win32"});const o=x(t,r);if(e?.startsWith("task:"))try{await n("schtasks",["/Run","/TN",t]);return}catch{}L("wscript.exe",["//B","//NoLogo",o])},async uninstall({serviceID:t,runCommand:e=f,homeDir:n=m.homedir()}){await e("schtasks",["/Delete","/TN",t,"/F"],{allowFailure:!0});const r=x(t,n);await y(r,{force:!0});const i=M(t,n);await y(i,{force:!0})},async discoverServices({homeDir:t=m.homedir(),runCommand:e=f}={}){const n=D("win32"),r=await e("schtasks",["/Query","/FO","CSV","/NH"],{allowFailure:!0}),i=[];if(Number(r?.exitCode??-1)===0){const a=String(r.stdout??"").split(/\r?\n/);for(const s of a){const u=s.match(/^"([^"]+)"/);if(!u)continue;const d=u[1];if(!d.startsWith(n))continue;let p=null;try{const w=x(d,t),T=(await P(w,"utf8")).match(/--config-dir\s+""([^""]+)""/);T&&(p=T[1])}catch{}i.push({serviceID:d,definitionPath:`task:${d}`,configDir:p})}}const o=c.join(t,"AppData","Roaming","Microsoft","Windows","Start Menu","Programs","Startup"),l=await F(o).catch(()=>[]);for(const a of l){if(!a.startsWith(n)||!a.endsWith(".lnk"))continue;const s=a.slice(0,-4);if(i.some(d=>d.serviceID===s))continue;let u=null;try{const d=x(s,t),w=(await P(d,"utf8")).match(/--config-dir\s+""([^""]+)""/);w&&(u=w[1])}catch{}i.push({serviceID:s,definitionPath:`startup:${s}`,configDir:u})}return i},async isServiceLoaded({serviceID:t,runCommand:e=f,homeDir:n=m.homedir()}){const r=await e("schtasks",["/Query","/TN",t,"/NH"],{allowFailure:!0});return Number(r?.exitCode??1)===0?!0:b(M(t,n))}}}function $t(){return{platform:"linux",kind:"systemd-user",async install({serviceID:t,nodePath:e,cliPath:n,configDir:r,rootDir:i,stdoutPath:o,stderrPath:l,environmentPath:a="",homeDir:s=m.homedir(),runCommand:u=f}){const d=it(t,s),p=N(i,o,l,s);return await k(c.dirname(d),{recursive:!0}),await $(d,ct({serviceID:t,nodePath:e,cliPath:n,configDir:r,rootDir:p,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:e=f}){await e("systemctl",["--user","start",`${t}.service`])},async stop({serviceID:t,runCommand:e=f}){await e("systemctl",["--user","stop",`${t}.service`],{allowFailure:!0})},async restart({serviceID:t,runCommand:e=f}){await e("systemctl",["--user","restart",`${t}.service`])},async uninstall({serviceID:t,definitionPath:e,runCommand:n=f}){await n("systemctl",["--user","stop",`${t}.service`],{allowFailure:!0}),await n("systemctl",["--user","disable",`${t}.service`],{allowFailure:!0}),await y(e,{force:!0}),await n("systemctl",["--user","daemon-reload"])},async discoverServices({homeDir:t=m.homedir()}={}){const e=c.join(t,".config","systemd","user"),n=await F(e).catch(()=>[]),r=D("linux"),i=[];for(const o of n){if(!o.startsWith(r)||!o.endsWith(".service"))continue;const l=o.slice(0,-8),a=c.join(e,o);let s=null;try{const u=await P(a,"utf8");s=rt(u)}catch{}i.push({serviceID:l,definitionPath:a,configDir:s})}return i},async isServiceLoaded({serviceID:t,runCommand:e=f}){const n=await e("systemctl",["--user","is-active",`${t}.service`],{allowFailure:!0});return String(n?.stdout??"").trim()==="active"}}}function E(t){try{const e=U(t,"utf8"),n=JSON.parse(e);if(n&&typeof n.service_id=="string"&&typeof n.node_path=="string"&&typeof n.cli_path=="string"&&typeof n.root_dir=="string")return n}catch{}return null}function Pt(t){return c.join(t,"daemon.lock.json")}function W(t){const e=Pt(t);try{const n=U(e,"utf8"),r=JSON.parse(n);if(typeof r?.pid=="number")return r.pid}catch{}return 0}function q(t){return c.join(t,".profile")}function St(t){return t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function xt(t){const e=[R(t.nodePath),R(t.cliPath)];t.configDir&&e.push("--config-dir",R(t.configDir));const n=`env ${v}=${R(t.rootDir)} ${e.join(" ")}`;return`${n} status >/dev/null 2>&1 || (nohup ${n} start >/dev/null 2>&1 &)`}function Et(t,e){return`# >>> grix-connector autostart [${t}] >>>
|
|
101
102
|
${e}
|
|
102
103
|
# <<< grix-connector autostart [${t}] <<<
|
|
103
|
-
`}function
|
|
104
|
-
${i}`).replace(/^\n+/,"");else{const
|
|
104
|
+
`}function K(t){const e=St(t);return new RegExp(`(?:^|\\n)# >>> grix-connector autostart \\[${e}\\] >>>\\n[\\s\\S]*?\\n# <<< grix-connector autostart \\[${e}\\] <<<\\n?`,"m")}async function kt(t,e,n){let r="";try{r=await P(t,"utf8")}catch{}const i=Et(e,n),o=K(e);let l;if(o.test(r))l=r.replace(o,`
|
|
105
|
+
${i}`).replace(/^\n+/,"");else{const a=r.length===0||r.endsWith(`
|
|
105
106
|
`)?"":`
|
|
106
|
-
`;l=`${r}${
|
|
107
|
-
`,{encoding:"utf8",mode:384});const
|
|
107
|
+
`;l=`${r}${a}${i}`}l!==r&&(await k(c.dirname(t),{recursive:!0}),await $(t,l,{encoding:"utf8"}))}async function vt(t,e){let n="";try{n=await P(t,"utf8")}catch{return}const r=K(e);if(!r.test(n))return;const i=n.replace(r,"").replace(/^\n+/,"");await $(t,i,{encoding:"utf8"})}function Ct(){return{platform:"linux",kind:"bare-daemon",async install({serviceID:t,nodePath:e,cliPath:n,configDir:r,rootDir:i,stdoutPath:o,stderrPath:l,homeDir:a=m.homedir()}){const s=S(t,a);await k(c.dirname(s),{recursive:!0});const u=N(i,o,l,a),d={schema_version:1,service_id:t,node_path:e,cli_path:n,config_dir:r??"",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 p=xt({nodePath:e,cliPath:n,configDir:r??"",rootDir:u});return await kt(q(a),t,p),{definitionPath:s}},async start({serviceID:t,homeDir:e=m.homedir()}){const n=S(t,e),r=E(n);if(!r)throw new Error(`bare-daemon marker missing: ${n}`);const i=[r.cli_path];r.config_dir&&i.push("--config-dir",r.config_dir),L(r.node_path,i,{env:{...process.env,[v]:r.root_dir}})},async stop({serviceID:t,homeDir:e=m.homedir()}){const n=S(t,e),r=E(n);if(!r)return;const i=W(r.root_dir);if(i>0&&I(i))try{process.kill(i,"SIGTERM")}catch{}},async restart(t){await this.stop(t);const e=Date.now()+5e3,n=S(t.serviceID,t.homeDir??m.homedir()),r=E(n);for(;r&&Date.now()<e;){const i=W(r.root_dir);if(i<=0||!I(i))break;await new Promise(o=>setTimeout(o,100))}await this.start(t)},async uninstall({serviceID:t,homeDir:e=m.homedir()}){const n=S(t,e),r=E(n);if(r){const i=W(r.root_dir);if(i>0&&I(i))try{process.kill(i,"SIGTERM")}catch{}}await y(n,{force:!0}),await vt(q(e),t)},async discoverServices({homeDir:t=m.homedir()}={}){const e=c.join(t,".grix","service"),n=await F(e).catch(()=>[]),r=D("linux"),i=[];for(const o of n){if(!o.startsWith(r)||!o.endsWith(".bare.json"))continue;const l=o.slice(0,-10),a=c.join(e,o),s=E(a);i.push({serviceID:l,definitionPath:a,configDir:s?.config_dir||null})}return i},async isServiceLoaded({serviceID:t,homeDir:e=m.homedir()}){const n=S(t,e),r=E(n);if(!r)return!1;const i=W(r.root_dir);return i>0&&I(i)}}}function Tt(t=process.getuid?.()??0){if(process.env.GRIX_FORCE_BARE_DAEMON==="1")return!1;const e=process.env.XDG_RUNTIME_DIR;return!!(e&&b(c.join(e,"bus"))||b(`/run/user/${t}/bus`))}function Wt(t=process.platform,e={}){return t==="darwin"?wt():t==="win32"?yt():e.systemdUserAvailable??Tt()?$t():Ct()}export{pt as WINDOWS_WRAPPER_TEMPLATE_MARKER,ht as WINDOWS_WRAPPER_TEMPLATE_VERSION,gt as buildWindowsWrapperScript,j as collectServicePortEnv,Wt as getPlatformServiceAdapter,Tt as isSystemdUserBusAvailable,vt as removeProfileAutostart,x as resolveWindowsWrapperPath,kt as upsertProfileAutostart};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "grix-connector",
|
|
3
|
-
"version": "4.6.
|
|
3
|
+
"version": "4.6.8",
|
|
4
4
|
"description": "Connect local AI coding agents (Claude, Codex, Gemini, Qwen, DeepSeek, Cursor, OpenCode, Pi, OpenHuman, Reasonix) to the Grix scheduling platform. Also serves as an OpenClaw plugin for Grix channel transport.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
Binary file
|