grix-connector 4.9.2-beta.1 → 4.9.2-beta.2

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.
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "bridgeVersion": "4.9.2-beta.1",
4
- "tarball": "grix-dsh-bridge-4.9.2-beta.1.tgz",
3
+ "bridgeVersion": "4.9.2-beta.2",
4
+ "tarball": "grix-dsh-bridge-4.9.2-beta.2.tgz",
5
5
  "size": 23140,
6
6
  "unpackedSize": 92726,
7
- "shasum": "adb6bedc5b7282626299902a4312fd69d5e92bc2",
8
- "integrity": "sha512-O6fc6V9EDi49ZpfOZIc9dPROuffQujk6TDZx03d53raGOUtbJvkHfEunl2UzHwmaz8JHlw6egFDPrVwPdcjPNw=="
7
+ "shasum": "043ac61a106ba3e1000b1bfda8899ac4238bb2a9",
8
+ "integrity": "sha512-gJe9ismowiHTI7dh+yb/dt4yiiOMTxvWXr3MRDz2oTGg3Zbn3hpf3CFzpN39d4pV7tNMq0qyE0JJ+xFVk5txbg=="
9
9
  }
@@ -1,12 +1,12 @@
1
- import{existsSync as F,readFileSync as V}from"node:fs";import{mkdir as k,readdir as b,readFile as E,rm as y,stat as rt,writeFile as $}from"node:fs/promises";import f from"node:os";import l from"node:path";import{GRIX_HOME_ENV as C}from"../core/config/paths.js";import{isProcessRunning as I,runCommand as p,spawnDetached as _,isWindowsElevated as it,killProcessesByCommandLine as X,findProcessesByCommandLine as ot}from"./process-control.js";import{getServicePrefix as R,parseConfigDirFromPlistXML as at,parseConfigDirFromSystemdUnit as st,resolveBareDaemonMarkerPath as P,resolveLinuxUserUnitPath as ct,resolveMacOSLaunchAgentPath as lt}from"./service-paths.js";function g(t){return String(t??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}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 ut(t){return`"${Q(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 J(t){return[t.nodePath,t.cliPath,...t.configDir?["--config-dir",t.configDir]:[]]}function dt(t){const e=J(t);return`<?xml version="1.0" encoding="UTF-8"?>
1
+ import{existsSync as C,readFileSync as V}from"node:fs";import{mkdir as v,readdir as I,readFile as P,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 S,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,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}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 n=[];for(const e of["GRIX_HEALTH_PORT","GRIX_ADMIN_PORT"]){const r=String(t[e]??"").trim();/^\d{2,5}$/.test(r)&&n.push([e,r])}return n}function J(t){return[t.nodePath,t.cliPath,...t.configDir?["--config-dir",t.configDir]:[]]}function wt(t){const n=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>
5
5
  <key>Label</key>
6
- <string>${g(t.serviceID)}</string>
6
+ <string>${w(t.serviceID)}</string>
7
7
  <key>ProgramArguments</key>
8
8
  <array>
9
- ${e.map(n=>` <string>${g(n)}</string>`).join(`
9
+ ${n.map(e=>` <string>${w(e)}</string>`).join(`
10
10
  `)}
11
11
  </array>
12
12
  <key>RunAtLoad</key>
@@ -17,32 +17,32 @@ ${e.map(n=>` <string>${g(n)}</string>`).join(`
17
17
  <key>ThrottleInterval</key>
18
18
  <integer>30</integer>
19
19
  <key>WorkingDirectory</key>
20
- <string>${g(l.dirname(t.cliPath))}</string>
20
+ <string>${w(c.dirname(t.cliPath))}</string>
21
21
  <key>EnvironmentVariables</key>
22
22
  <dict>
23
- <key>${C}</key>
24
- <string>${g(t.rootDir)}</string>
25
- ${j().map(([n,r])=>` <key>${n}</key>
23
+ <key>${T}</key>
24
+ <string>${w(t.rootDir)}</string>
25
+ ${j().map(([e,r])=>` <key>${e}</key>
26
26
  <string>${r}</string>
27
27
  `).join("")}${t.environmentPath?` <key>PATH</key>
28
- <string>${g(t.environmentPath)}</string>
28
+ <string>${w(t.environmentPath)}</string>
29
29
  `:""} </dict>
30
30
  <key>StandardOutPath</key>
31
- <string>${g(t.stdoutPath)}</string>
31
+ <string>${w(t.stdoutPath)}</string>
32
32
  <key>StandardErrorPath</key>
33
- <string>${g(t.stderrPath)}</string>
33
+ <string>${w(t.stderrPath)}</string>
34
34
  </dict>
35
35
  </plist>
36
- `}function mt(t){const e=J(t).map(n=>ut(n)).join(" ");return`[Unit]
36
+ `}function yt(t){const n=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=${e}
43
- WorkingDirectory=${O(l.dirname(t.cliPath))}
44
- Environment=${z(`${C}=${t.rootDir}`)}
45
- ${j().map(([n,r])=>`Environment=${n}=${r}
42
+ ExecStart=${n}
43
+ WorkingDirectory=${O(c.dirname(t.cliPath))}
44
+ Environment=${z(`${T}=${t.rootDir}`)}
45
+ ${j().map(([e,r])=>`Environment=${e}=${r}
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 S(t,e){const n=t.replace(/[^a-zA-Z0-9._-]/g,"_");return l.join(e,".grix",`${n}-wrapper.vbs`)}function M(t,e){const n=t.replace(/[^a-zA-Z0-9._-]/g,"_"),r=l.join(e,"AppData","Roaming","Microsoft","Windows","Start Menu","Programs","Startup");return l.join(r,`${n}.lnk`)}function m(t){return String(t??"").replace(/"/g,'""')}function L(t){return`'${String(t??"").replace(/'/g,"''")}'`}function ft(t,e){const n=l.join(l.dirname(t),l.basename(e).replace(/\.lnk$/,"-create.vbs")),r=["Option Explicit","Dim shell, shortcut",'Set shell = CreateObject("WScript.Shell")',`Set shortcut = shell.CreateShortcut("${m(e)}")`,'shortcut.TargetPath = "wscript.exe"',`shortcut.Arguments = "//B //NoLogo \\"${m(t)}\\""`,"shortcut.WindowStyle = 7","shortcut.Save",""].join(`\r
56
- `);return{path:n,content:r}}async function pt(t){const{wrapperPath:e,shortcutPath:n,runCommand:r}=t,i=ft(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(F(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 ht(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 gt(t){const e=`//B //NoLogo "${t.wrapperPath}"`;return`<?xml version="1.0" encoding="UTF-16"?>
55
+ `}function x(t,n){const e=t.replace(/[^a-zA-Z0-9._-]/g,"_");return c.join(n,".grix",`${e}-wrapper.vbs`)}function M(t,n){const e=t.replace(/[^a-zA-Z0-9._-]/g,"_"),r=c.join(n,"AppData","Roaming","Microsoft","Windows","Start Menu","Programs","Startup");return c.join(r,`${e}.lnk`)}function m(t){return String(t??"").replace(/"/g,'""')}function A(t){return`'${String(t??"").replace(/'/g,"''")}'`}function $t(t,n){const e=c.join(c.dirname(t),c.basename(n).replace(/\.lnk$/,"-create.vbs")),r=["Option Explicit","Dim shell, shortcut",'Set shell = CreateObject("WScript.Shell")',`Set shortcut = shell.CreateShortcut("${m(n)}")`,'shortcut.TargetPath = "wscript.exe"',`shortcut.Arguments = "//B //NoLogo \\"${m(t)}\\""`,"shortcut.WindowStyle = 7","shortcut.Save",""].join(`\r
56
+ `);return{path:e,content:r}}async function Et(t){const{wrapperPath:n,shortcutPath:e,runCommand:r}=t,i=$t(n,e);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(C(e))return!0}return console.warn(`Warning: failed to create Windows logon-autostart shortcut at ${e}. 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 Pt(t){try{const n=await t("whoami",["/user","/fo","csv","/nh"],{allowFailure:!0}),e=String(n?.stdout??"").match(/"(S-1-[0-9-]+)"/);if(e)return e[1]}catch{}return null}function St(t){const n=`//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>
@@ -61,12 +61,12 @@ WantedBy=default.target
61
61
  <Triggers>
62
62
  <LogonTrigger>
63
63
  <Enabled>true</Enabled>
64
- <UserId>${g(t.userId)}</UserId>
64
+ <UserId>${w(t.userId)}</UserId>
65
65
  </LogonTrigger>
66
66
  </Triggers>
67
67
  <Principals>
68
68
  <Principal id="Author">
69
- <UserId>${g(t.userId)}</UserId>
69
+ <UserId>${w(t.userId)}</UserId>
70
70
  <LogonType>InteractiveToken</LogonType>
71
71
  <RunLevel>LeastPrivilege</RunLevel>
72
72
  </Principal>
@@ -92,17 +92,17 @@ WantedBy=default.target
92
92
  <Actions Context="Author">
93
93
  <Exec>
94
94
  <Command>wscript.exe</Command>
95
- <Arguments>${g(e)}</Arguments>
95
+ <Arguments>${w(n)}</Arguments>
96
96
  </Exec>
97
97
  </Actions>
98
98
  </Task>
99
- `}async function wt(t){const{serviceID:e,wrapperPath:n,runCommand:r}=t,i=await ht(r)??f.userInfo().username,o=l.join(l.dirname(n),`${e}-task.xml`);try{const a=gt({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 yt=4,$t="grix-wrapper-template:";function Et(t){const e=l.join(t.rootDir,"data","upgrade-wrapper-child.json"),n=[`"${t.cliPath}"`,...t.configDir?["--config-dir",`"${t.configDir}"`]:[]],r=["$ErrorActionPreference = 'Stop'",`$recordPath = ${L(e)}`,"$exitCode = 1","try {"," [IO.Directory]::CreateDirectory([IO.Path]::GetDirectoryName($recordPath)) | Out-Null",` $p = Start-Process -FilePath ${L(t.nodePath)} -ArgumentList @(${n.map(L).join(", ")}) -WindowStyle Hidden -PassThru`,` $record = @{ pid = $p.Id; launched_at = [DateTimeOffset]::UtcNow.ToUnixTimeMilliseconds(); boot_time = [DateTimeOffset]::UtcNow.ToUnixTimeMilliseconds() - [Environment]::TickCount64; cli_path = ${L(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"),c=`"${l.join(process.env.SystemRoot||"C:\\Windows","System32","WindowsPowerShell","v1.0","powershell.exe")}" -NoProfile -NonInteractive -ExecutionPolicy Bypass -EncodedCommand ${i}`,a=l.join(t.rootDir,"bin","upgrade-guardian.mjs"),s=l.join(t.rootDir,"bin","upgrade-guardian.fallback.mjs"),u=l.join(t.rootDir,"data","upgrade-wrapper.pause.json"),d=l.join(t.rootDir,"data","upgrade-pending.json"),h=l.join(t.rootDir,"data"),w=l.join(h,"wrapper.lock"),W=[`"${m(t.nodePath)}"`,`"${m(a)}"`,"activate","--root",`"${m(t.rootDir)}"`].join(" "),T=`${W} --wrapper-handoff`,H=[`"${m(t.nodePath)}"`,`"${m(s)}"`,"activate","--root",`"${m(t.rootDir)}"`].join(" "),tt=`${H} --wrapper-handoff`;return[`' ${$t} ${yt}`,"Option Explicit","Dim shell, processEnv, fso, command, guardianCommand, handoffGuardianCommand, guardianFallbackCommand, handoffGuardianFallbackCommand, guardianPath, guardianFallbackPath, maintenanceFile, pendingFile, delayMs, rapidCount, guardianExit, wrapperLockDir, wrapperLockFile, wrapperLock",`command = "${m(c)}"`,`guardianCommand = "${m(W)}"`,`handoffGuardianCommand = "${m(T)}"`,`guardianFallbackCommand = "${m(H)}"`,`handoffGuardianFallbackCommand = "${m(tt)}"`,`guardianPath = "${m(a)}"`,`guardianFallbackPath = "${m(s)}"`,`maintenanceFile = "${m(u)}"`,`pendingFile = "${m(d)}"`,`wrapperLockDir = "${m(h)}"`,`wrapperLockFile = "${m(w)}"`,'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("${C}") = "${m(t.rootDir)}"`,'processEnv("GRIX_WRAPPER_SUPERVISED") = "1"',...j().map(([et,nt])=>`processEnv("${et}") = "${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 v(t){return`gui/${t??0}`}function Pt(t=process.env){return t.GRIX_LAUNCHER_MANAGED==="1"||!!t.GRIX_CLAUDE_INTERNAL_API_URL}function B(t){const e=String(t?.stdout??"").trim();return String(t?.stderr??"").trim()||e||`exit=${Number(t?.exitCode??-1)}`}function A(t,e,n,r){if(t?.trim())return l.resolve(t);const i=e||n;return i?l.resolve(l.dirname(l.dirname(i))):l.join(r,".grix")}async function K(t){try{await rt(t)}catch{throw new Error(`launchd plist missing: ${t}`)}}async function q(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 c=await r("launchctl",["print",i],{allowFailure:!0});if(Number(c?.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 c=0;c<20;c+=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 G(t){const{serviceID:e,domain:n,definitionPath:r,runCommand:i}=t,o=`${n}/${e}`,c=await i("launchctl",["bootstrap",n,r],{allowFailure:!0});if(Number(c?.exitCode??-1)===0)return;const a=await i("launchctl",["print",o],{allowFailure:!0});Number(a?.exitCode??1)===0&&await q(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(c)}; retry=${B(s)}`)}function St(){return{platform:"darwin",kind:"launchd",async install({serviceID:t,nodePath:e,cliPath:n,configDir:r,rootDir:i,stdoutPath:o,stderrPath:c,environmentPath:a="",homeDir:s=f.homedir()}){const u=lt(t,s),d=A(i,o,c,s);return await k(l.dirname(u),{recursive:!0}),await $(u,dt({serviceID:t,nodePath:e,cliPath:n,configDir:r,rootDir:d,stdoutPath:o,stderrPath:c,environmentPath:a}),{encoding:"utf8",mode:384}),{definitionPath:u}},async start({serviceID:t,definitionPath:e,runCommand:n=p,uid:r=process.getuid?.()??0}){const i=v(r);await K(e),await G({serviceID:t,domain:i,definitionPath:e,runCommand:n})},async stop({serviceID:t,runCommand:e=p,uid:n=process.getuid?.()??0}){const r=v(n);await e("launchctl",["bootout",`${r}/${t}`],{allowFailure:!0})},async restart({serviceID:t,definitionPath:e,runCommand:n=p,uid:r=process.getuid?.()??0,env:i=process.env,reloadDefinition:o=!1}){const c=v(r),a={serviceID:t,domain:c,definitionPath:e,runCommand:n};if(await K(e),!o&&Pt(i)){const s=await n("launchctl",["kickstart","-k",`${c}/${t}`],{allowFailure:!0});if(Number(s?.exitCode??-1)===0)return;await G(a);return}await q(a),await G(a)},async uninstall({serviceID:t,definitionPath:e,runCommand:n=p,uid:r=process.getuid?.()??0}){const i=v(r);await n("launchctl",["bootout",`${i}/${t}`],{allowFailure:!0}),await y(e,{force:!0})},async discoverServices({homeDir:t=f.homedir()}={}){const e=l.join(t,"Library","LaunchAgents"),n=await b(e).catch(()=>[]),r=R("darwin"),i=[];for(const o of n){if(!o.startsWith(r)||!o.endsWith(".plist"))continue;const c=o.slice(0,-6),a=l.join(e,o);let s=null;try{const u=await E(a,"utf8");s=at(u)}catch{}i.push({serviceID:c,definitionPath:a,configDir:s})}return i},async isServiceLoaded({serviceID:t,runCommand:e=p,uid:n=process.getuid?.()??0}){const r=v(n),i=await e("launchctl",["print",`${r}/${t}`],{allowFailure:!0});return Number(i?.exitCode??1)===0}}}function xt(t){return`${t}-wrapper.vbs`}const kt=5e3;async function U(t,e){const n=await ot(xt(t),{runCommandImpl:e,platform:"win32"}).catch(()=>[]),r=new Set([process.pid,process.ppid]);return n.filter(i=>!r.has(i))}async function Ct(t,e,n=kt){const r=Date.now()+n;let i=await U(t,e);for(;i.length>0&&Date.now()<r;)await new Promise(o=>setTimeout(o,250)),i=await U(t,e);return i}function vt(){return{platform:"win32",kind:"task-scheduler",async install({serviceID:t,nodePath:e,cliPath:n,configDir:r,rootDir:i,stdoutPath:o,stderrPath:c,runCommand:a=p,homeDir:s=f.homedir()}){const u=S(t,s),d=A(i,o,c,s);await k(l.dirname(u),{recursive:!0}),await $(u,Et({nodePath:e,cliPath:n,configDir:r,rootDir:d}),"utf8");let h=!1;it()&&(h=await wt({serviceID:t,wrapperPath:u,runCommand:a}));const w=M(t,s);return h?await y(w,{force:!0}).catch(()=>{}):await pt({wrapperPath:u,shortcutPath:w,runCommand:a}),{definitionPath:h?`task:${t}`:`startup:${t}`}},async start({serviceID:t,definitionPath:e,runCommand:n=p,homeDir:r=f.homedir()}){const i=S(t,r);if(e.startsWith("task:"))try{await n("schtasks",["/Run","/TN",t]);return}catch{}(await U(t,n)).length>0||_("wscript.exe",["//B","//NoLogo",i])},async stop({serviceID:t,runCommand:e=p,homeDir:n=f.homedir()}){await e("schtasks",["/End","/TN",t],{allowFailure:!0});const r=`${t}-wrapper.vbs`;await X(r,{platform:"win32"})},async restart({serviceID:t,definitionPath:e,runCommand:n=p,homeDir:r=f.homedir()}){await n("schtasks",["/End","/TN",t],{allowFailure:!0});const i=`${t}-wrapper.vbs`;await X(i,{platform:"win32"});const o=S(t,r);if(e?.startsWith("task:"))try{await n("schtasks",["/Run","/TN",t]);return}catch{}(await Ct(t,n)).length>0||_("wscript.exe",["//B","//NoLogo",o])},async uninstall({serviceID:t,runCommand:e=p,homeDir:n=f.homedir()}){await e("schtasks",["/Delete","/TN",t,"/F"],{allowFailure:!0});const r=S(t,n);await y(r,{force:!0});const i=M(t,n);await y(i,{force:!0})},async discoverServices({homeDir:t=f.homedir(),runCommand:e=p}={}){const n=R("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 h=null;try{const w=S(d,t),T=(await E(w,"utf8")).match(/--config-dir\s+""([^""]+)""/);T&&(h=T[1])}catch{}i.push({serviceID:d,definitionPath:`task:${d}`,configDir:h})}}const o=l.join(t,"AppData","Roaming","Microsoft","Windows","Start Menu","Programs","Startup"),c=await b(o).catch(()=>[]);for(const a of c){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=S(s,t),w=(await E(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=p,homeDir:n=f.homedir()}){const r=await e("schtasks",["/Query","/TN",t,"/NH"],{allowFailure:!0});return Number(r?.exitCode??1)===0?!0:F(M(t,n))}}}function Tt(){return{platform:"linux",kind:"systemd-user",async install({serviceID:t,nodePath:e,cliPath:n,configDir:r,rootDir:i,stdoutPath:o,stderrPath:c,environmentPath:a="",homeDir:s=f.homedir(),runCommand:u=p}){const d=ct(t,s),h=A(i,o,c,s);return await k(l.dirname(d),{recursive:!0}),await $(d,mt({serviceID:t,nodePath:e,cliPath:n,configDir:r,rootDir:h,stdoutPath:o,stderrPath:c,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=p}){await e("systemctl",["--user","start",`${t}.service`])},async stop({serviceID:t,runCommand:e=p}){await e("systemctl",["--user","stop",`${t}.service`],{allowFailure:!0})},async restart({serviceID:t,runCommand:e=p}){await e("systemctl",["--user","restart",`${t}.service`])},async uninstall({serviceID:t,definitionPath:e,runCommand:n=p}){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=f.homedir()}={}){const e=l.join(t,".config","systemd","user"),n=await b(e).catch(()=>[]),r=R("linux"),i=[];for(const o of n){if(!o.startsWith(r)||!o.endsWith(".service"))continue;const c=o.slice(0,-8),a=l.join(e,o);let s=null;try{const u=await E(a,"utf8");s=st(u)}catch{}i.push({serviceID:c,definitionPath:a,configDir:s})}return i},async isServiceLoaded({serviceID:t,runCommand:e=p}){const n=await e("systemctl",["--user","is-active",`${t}.service`],{allowFailure:!0});return String(n?.stdout??"").trim()==="active"}}}function x(t){try{const e=V(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 Ft(t){return l.join(t,"daemon.lock.json")}function N(t){const e=Ft(t);try{const n=V(e,"utf8"),r=JSON.parse(n);if(typeof r?.pid=="number")return r.pid}catch{}return 0}function Y(t){return l.join(t,".profile")}function bt(t){return t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function It(t){const e=[D(t.nodePath),D(t.cliPath)];t.configDir&&e.push("--config-dir",D(t.configDir));const n=`env ${C}=${D(t.rootDir)} ${e.join(" ")}`;return`${n} status >/dev/null 2>&1 || (nohup ${n} start >/dev/null 2>&1 &)`}function Rt(t,e){return`# >>> grix-connector autostart [${t}] >>>
102
- ${e}
99
+ `}async function xt(t){const{serviceID:n,wrapperPath:e,runCommand:r}=t,i=await Pt(r)??p.userInfo().username,o=c.join(c.dirname(e),`${n}-task.xml`);try{const a=St({userId:i,wrapperPath:e});return await $(o,"\uFEFF"+a,"utf16le"),await r("schtasks",["/Create","/TN",n,"/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 n=c.join(t.rootDir,"data","upgrade-wrapper-child.json"),e=[`"${t.cliPath}"`,...t.configDir?["--config-dir",`"${t.configDir}"`]:[]],r=["$ErrorActionPreference = 'Stop'",`$recordPath = ${A(n)}`,"$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(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"),h=c.join(t.rootDir,"data"),g=c.join(h,"wrapper.lock"),E=[`"${m(t.nodePath)}"`,`"${m(a)}"`,"activate","--root",`"${m(t.rootDir)}"`].join(" "),b=`${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(b)}"`,`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(([nt,rt])=>`processEnv("${nt}") = "${rt}"`),"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,n){return c.join(ht(t,n),"dist","service","platform-adapter.js")}async function Tt(t,n={}){const e={version:K,build:Ct};try{if(c.basename(t)!==pt)return e;const r=c.dirname(t),i=ft(r,"current");if(!i)return e;const o=vt(r,i),l=n.selfModulePath??ot(import.meta.url);if(c.resolve(o)===c.resolve(l)||!C(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 F(t){return`gui/${t??0}`}function Ft(t=process.env){return t.GRIX_LAUNCHER_MANAGED==="1"||!!t.GRIX_CLAUDE_INTERNAL_API_URL}function U(t){const n=String(t?.stdout??"").trim();return String(t?.stderr??"").trim()||n||`exit=${Number(t?.exitCode??-1)}`}function N(t,n,e,r){if(t?.trim())return c.resolve(t);const i=n||e;return i?c.resolve(c.dirname(c.dirname(i))):c.join(r,".grix")}async function q(t){try{await it(t)}catch{throw new Error(`launchd plist missing: ${t}`)}}async function Y(t){const{serviceID:n,domain:e,runCommand:r}=t,i=`${e}/${n}`,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}: ${U(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 B(t){const{serviceID:n,domain:e,definitionPath:r,runCommand:i}=t,o=`${e}/${n}`,l=await i("launchctl",["bootstrap",e,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 Y(t);const s=await i("launchctl",["bootstrap",e,r],{allowFailure:!0});if(Number(s?.exitCode??-1)!==0)throw new Error(`launchctl bootstrap ${e} failed: initial=${U(l)}; retry=${U(s)}`)}function bt(){return{platform:"darwin",kind:"launchd",async install({serviceID:t,nodePath:n,cliPath:e,configDir:r,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 v(c.dirname(u),{recursive:!0}),await $(u,wt({serviceID:t,nodePath:n,cliPath:e,configDir:r,rootDir:d,stdoutPath:o,stderrPath:l,environmentPath:a}),{encoding:"utf8",mode:384}),{definitionPath:u}},async start({serviceID:t,definitionPath:n,runCommand:e=f,uid:r=process.getuid?.()??0}){const i=F(r);await q(n),await B({serviceID:t,domain:i,definitionPath:n,runCommand:e})},async stop({serviceID:t,runCommand:n=f,uid:e=process.getuid?.()??0}){const r=F(e);await n("launchctl",["bootout",`${r}/${t}`],{allowFailure:!0})},async restart({serviceID:t,definitionPath:n,runCommand:e=f,uid:r=process.getuid?.()??0,env:i=process.env,reloadDefinition:o=!1}){const l=F(r),a={serviceID:t,domain:l,definitionPath:n,runCommand:e};if(await q(n),!o&&Ft(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:n,runCommand:e=f,uid:r=process.getuid?.()??0}){const i=F(r);await e("launchctl",["bootout",`${i}/${t}`],{allowFailure:!0}),await y(n,{force:!0})},async discoverServices({homeDir:t=p.homedir()}={}){const n=c.join(t,"Library","LaunchAgents"),e=await I(n).catch(()=>[]),r=L("darwin"),i=[];for(const o of e){if(!o.startsWith(r)||!o.endsWith(".plist"))continue;const l=o.slice(0,-6),a=c.join(n,o);let s=null;try{const u=await P(a,"utf8");s=lt(u)}catch{}i.push({serviceID:l,definitionPath:a,configDir:s})}return i},async isServiceLoaded({serviceID:t,runCommand:n=f,uid:e=process.getuid?.()??0}){const r=F(e),i=await n("launchctl",["print",`${r}/${t}`],{allowFailure:!0});return Number(i?.exitCode??1)===0}}}function It(t){return`${t}-wrapper.vbs`}const Rt=5e3;async function G(t,n){const e=await ct(It(t),{runCommandImpl:n,platform:"win32"}).catch(()=>[]),r=new Set([process.pid,process.ppid]);return e.filter(i=>!r.has(i))}async function Lt(t,n,e=Rt){const r=Date.now()+e;let i=await G(t,n);for(;i.length>0&&Date.now()<r;)await new Promise(o=>setTimeout(o,250)),i=await G(t,n);return i}function Dt(){return{platform:"win32",kind:"task-scheduler",async install({serviceID:t,nodePath:n,cliPath:e,configDir:r,rootDir:i,stdoutPath:o,stderrPath:l,runCommand:a=f,homeDir:s=p.homedir()}){const u=x(t,s),d=N(i,o,l,s);await v(c.dirname(u),{recursive:!0});const h=await Tt(e);await $(u,h.build({nodePath:n,cliPath:e,configDir:r,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:n,runCommand:e=f,homeDir:r=p.homedir()}){const i=x(t,r);if(n.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:n=f,homeDir:e=p.homedir()}){await n("schtasks",["/End","/TN",t],{allowFailure:!0});const r=`${t}-wrapper.vbs`;await X(r,{platform:"win32"})},async restart({serviceID:t,definitionPath:n,runCommand:e=f,homeDir:r=p.homedir()}){await e("schtasks",["/End","/TN",t],{allowFailure:!0});const i=`${t}-wrapper.vbs`;await X(i,{platform:"win32"});const o=x(t,r);if(n?.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:n=f,homeDir:e=p.homedir()}){await n("schtasks",["/Delete","/TN",t,"/F"],{allowFailure:!0});const r=x(t,e);await y(r,{force:!0});const i=M(t,e);await y(i,{force:!0})},async discoverServices({homeDir:t=p.homedir(),runCommand:n=f}={}){const e=L("win32"),r=await n("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(e))continue;let h=null;try{const g=x(d,t),b=(await P(g,"utf8")).match(/--config-dir\s+""([^""]+)""/);b&&(h=b[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=x(s,t),g=(await P(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:n=f,homeDir:e=p.homedir()}){const r=await n("schtasks",["/Query","/TN",t,"/NH"],{allowFailure:!0});return Number(r?.exitCode??1)===0?!0:C(M(t,e))}}}function At(){return{platform:"linux",kind:"systemd-user",async install({serviceID:t,nodePath:n,cliPath:e,configDir:r,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 v(c.dirname(d),{recursive:!0}),await $(d,yt({serviceID:t,nodePath:n,cliPath:e,configDir:r,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:n=f}){await n("systemctl",["--user","start",`${t}.service`])},async stop({serviceID:t,runCommand:n=f}){await n("systemctl",["--user","stop",`${t}.service`],{allowFailure:!0})},async restart({serviceID:t,runCommand:n=f}){await n("systemctl",["--user","restart",`${t}.service`])},async uninstall({serviceID:t,definitionPath:n,runCommand:e=f}){await e("systemctl",["--user","stop",`${t}.service`],{allowFailure:!0}),await e("systemctl",["--user","disable",`${t}.service`],{allowFailure:!0}),await y(n,{force:!0}),await e("systemctl",["--user","daemon-reload"])},async discoverServices({homeDir:t=p.homedir()}={}){const n=c.join(t,".config","systemd","user"),e=await I(n).catch(()=>[]),r=L("linux"),i=[];for(const o of e){if(!o.startsWith(r)||!o.endsWith(".service"))continue;const l=o.slice(0,-8),a=c.join(n,o);let s=null;try{const u=await P(a,"utf8");s=ut(u)}catch{}i.push({serviceID:l,definitionPath:a,configDir:s})}return i},async isServiceLoaded({serviceID:t,runCommand:n=f}){const e=await n("systemctl",["--user","is-active",`${t}.service`],{allowFailure:!0});return String(e?.stdout??"").trim()==="active"}}}function k(t){try{const n=V(t,"utf8"),e=JSON.parse(n);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 n=Nt(t);try{const e=V(n,"utf8"),r=JSON.parse(e);if(typeof r?.pid=="number")return r.pid}catch{}return 0}function Z(t){return c.join(t,".profile")}function Wt(t){return t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function _t(t){const n=[D(t.nodePath),D(t.cliPath)];t.configDir&&n.push("--config-dir",D(t.configDir));const e=`env ${T}=${D(t.rootDir)} ${n.join(" ")}`;return`${e} status >/dev/null 2>&1 || (nohup ${e} start >/dev/null 2>&1 &)`}function Ot(t,n){return`# >>> grix-connector autostart [${t}] >>>
102
+ ${n}
103
103
  # <<< grix-connector autostart [${t}] <<<
104
- `}function Z(t){const e=bt(t);return new RegExp(`(?:^|\\n)# >>> grix-connector autostart \\[${e}\\] >>>\\n[\\s\\S]*?\\n# <<< grix-connector autostart \\[${e}\\] <<<\\n?`,"m")}async function Dt(t,e,n){let r="";try{r=await E(t,"utf8")}catch{}const i=Rt(e,n),o=Z(e);let c;if(o.test(r))c=r.replace(o,`
104
+ `}function tt(t){const n=Wt(t);return new RegExp(`(?:^|\\n)# >>> grix-connector autostart \\[${n}\\] >>>\\n[\\s\\S]*?\\n# <<< grix-connector autostart \\[${n}\\] <<<\\n?`,"m")}async function jt(t,n,e){let r="";try{r=await P(t,"utf8")}catch{}const i=Ot(n,e),o=tt(n);let l;if(o.test(r))l=r.replace(o,`
105
105
  ${i}`).replace(/^\n+/,"");else{const a=r.length===0||r.endsWith(`
106
106
  `)?"":`
107
- `;c=`${r}${a}${i}`}c!==r&&(await k(l.dirname(t),{recursive:!0}),await $(t,c,{encoding:"utf8"}))}async function Lt(t,e){let n="";try{n=await E(t,"utf8")}catch{return}const r=Z(e);if(!r.test(n))return;const i=n.replace(r,"").replace(/^\n+/,"");await $(t,i,{encoding:"utf8"})}function At(){return{platform:"linux",kind:"bare-daemon",async install({serviceID:t,nodePath:e,cliPath:n,configDir:r,rootDir:i,stdoutPath:o,stderrPath:c,homeDir:a=f.homedir()}){const s=P(t,a);await k(l.dirname(s),{recursive:!0});const u=A(i,o,c,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:c,installed_at:Date.now()};await $(s,`${JSON.stringify(d,null,2)}
108
- `,{encoding:"utf8",mode:384});const h=It({nodePath:e,cliPath:n,configDir:r??"",rootDir:u});return await Dt(Y(a),t,h),{definitionPath:s}},async start({serviceID:t,homeDir:e=f.homedir()}){const n=P(t,e),r=x(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),_(r.node_path,i,{env:{...process.env,[C]:r.root_dir}})},async stop({serviceID:t,homeDir:e=f.homedir()}){const n=P(t,e),r=x(n);if(!r)return;const i=N(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=P(t.serviceID,t.homeDir??f.homedir()),r=x(n);for(;r&&Date.now()<e;){const i=N(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=f.homedir()}){const n=P(t,e),r=x(n);if(r){const i=N(r.root_dir);if(i>0&&I(i))try{process.kill(i,"SIGTERM")}catch{}}await y(n,{force:!0}),await Lt(Y(e),t)},async discoverServices({homeDir:t=f.homedir()}={}){const e=l.join(t,".grix","service"),n=await b(e).catch(()=>[]),r=R("linux"),i=[];for(const o of n){if(!o.startsWith(r)||!o.endsWith(".bare.json"))continue;const c=o.slice(0,-10),a=l.join(e,o),s=x(a);i.push({serviceID:c,definitionPath:a,configDir:s?.config_dir||null})}return i},async isServiceLoaded({serviceID:t,homeDir:e=f.homedir()}){const n=P(t,e),r=x(n);if(!r)return!1;const i=N(r.root_dir);return i>0&&I(i)}}}function Nt(t=process.getuid?.()??0){if(process.env.GRIX_FORCE_BARE_DAEMON==="1")return!1;const e=process.env.XDG_RUNTIME_DIR;return!!(e&&F(l.join(e,"bus"))||F(`/run/user/${t}/bus`))}function Ut(t=process.platform,e={}){return t==="darwin"?St():t==="win32"?vt():e.systemdUserAvailable??Nt()?Tt():At()}export{$t as WINDOWS_WRAPPER_TEMPLATE_MARKER,yt as WINDOWS_WRAPPER_TEMPLATE_VERSION,Et as buildWindowsWrapperScript,j as collectServicePortEnv,Ut as getPlatformServiceAdapter,Pt as isInsideManagedDaemonTree,Nt as isSystemdUserBusAvailable,Lt as removeProfileAutostart,M as resolveWindowsStartupShortcutPath,S as resolveWindowsWrapperPath,Dt as upsertProfileAutostart};
107
+ `;l=`${r}${a}${i}`}l!==r&&(await v(c.dirname(t),{recursive:!0}),await $(t,l,{encoding:"utf8"}))}async function Mt(t,n){let e="";try{e=await P(t,"utf8")}catch{return}const r=tt(n);if(!r.test(e))return;const i=e.replace(r,"").replace(/^\n+/,"");await $(t,i,{encoding:"utf8"})}function Ut(){return{platform:"linux",kind:"bare-daemon",async install({serviceID:t,nodePath:n,cliPath:e,configDir:r,rootDir:i,stdoutPath:o,stderrPath:l,homeDir:a=p.homedir()}){const s=S(t,a);await v(c.dirname(s),{recursive:!0});const u=N(i,o,l,a),d={schema_version:1,service_id:t,node_path:n,cli_path:e,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 h=_t({nodePath:n,cliPath:e,configDir:r??"",rootDir:u});return await jt(Z(a),t,h),{definitionPath:s}},async start({serviceID:t,homeDir:n=p.homedir()}){const e=S(t,n),r=k(e);if(!r)throw new Error(`bare-daemon marker missing: ${e}`);const i=[r.cli_path];r.config_dir&&i.push("--config-dir",r.config_dir),_(r.node_path,i,{env:{...process.env,[T]:r.root_dir}})},async stop({serviceID:t,homeDir:n=p.homedir()}){const e=S(t,n),r=k(e);if(!r)return;const i=W(r.root_dir);if(i>0&&R(i))try{process.kill(i,"SIGTERM")}catch{}},async restart(t){await this.stop(t);const n=Date.now()+5e3,e=S(t.serviceID,t.homeDir??p.homedir()),r=k(e);for(;r&&Date.now()<n;){const i=W(r.root_dir);if(i<=0||!R(i))break;await new Promise(o=>setTimeout(o,100))}await this.start(t)},async uninstall({serviceID:t,homeDir:n=p.homedir()}){const e=S(t,n),r=k(e);if(r){const i=W(r.root_dir);if(i>0&&R(i))try{process.kill(i,"SIGTERM")}catch{}}await y(e,{force:!0}),await Mt(Z(n),t)},async discoverServices({homeDir:t=p.homedir()}={}){const n=c.join(t,".grix","service"),e=await I(n).catch(()=>[]),r=L("linux"),i=[];for(const o of e){if(!o.startsWith(r)||!o.endsWith(".bare.json"))continue;const l=o.slice(0,-10),a=c.join(n,o),s=k(a);i.push({serviceID:l,definitionPath:a,configDir:s?.config_dir||null})}return i},async isServiceLoaded({serviceID:t,homeDir:n=p.homedir()}){const e=S(t,n),r=k(e);if(!r)return!1;const i=W(r.root_dir);return i>0&&R(i)}}}function Bt(t=process.getuid?.()??0){if(process.env.GRIX_FORCE_BARE_DAEMON==="1")return!1;const n=process.env.XDG_RUNTIME_DIR;return!!(n&&C(c.join(n,"bus"))||C(`/run/user/${t}/bus`))}function Yt(t=process.platform,n={}){return t==="darwin"?bt():t==="win32"?Dt():n.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,Ft as isInsideManagedDaemonTree,Bt as isSystemdUserBusAvailable,Mt as removeProfileAutostart,M as resolveWindowsStartupShortcutPath,x as resolveWindowsWrapperPath,Tt as resolveWindowsWrapperTemplateSource,jt as upsertProfileAutostart};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "grix-connector",
3
- "version": "4.9.2-beta.1",
3
+ "version": "4.9.2-beta.2",
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",