@@ -28,35 +28,59 @@ function logPath(): string {
2828 return join ( getConfigDir ( ) , "service.log" ) ;
2929}
3030
31+ function plistString ( value : string ) : string {
32+ return value
33+ . replace ( / & / g, "&" )
34+ . replace ( / < / g, "<" )
35+ . replace ( / > / g, ">" )
36+ . replace ( / " / g, """ )
37+ . replace ( / ' / g, "'" ) ;
38+ }
39+
3140export function buildPlist ( ) : string {
3241 const { bun, cli } = cliEntry ( ) ;
3342 const log = logPath ( ) ;
3443 const path = process . env . PATH ?? "/usr/local/bin:/usr/bin:/bin" ;
44+ const codexHome = process . env . CODEX_HOME ?. trim ( ) ;
45+ const codexHomeXml = codexHome ? ` <key>CODEX_HOME</key><string>${ plistString ( codexHome ) } </string>` : "" ;
3546 return `<?xml version="1.0" encoding="UTF-8"?>
3647<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3748<plist version="1.0">
3849<dict>
3950 <key>Label</key><string>${ LABEL } </string>
4051 <key>ProgramArguments</key>
4152 <array>
42- <string>${ bun } </string>
43- <string>${ cli } </string>
53+ <string>${ plistString ( bun ) } </string>
54+ <string>${ plistString ( cli ) } </string>
4455 <string>start</string>
4556 </array>
4657 <key>RunAtLoad</key><true/>
4758 <key>KeepAlive</key><true/>
4859 <key>EnvironmentVariables</key>
4960 <dict>
5061 <key>OCX_SERVICE</key><string>1</string>
51- <key>PATH</key><string>${ path } </string>
52- </dict>
53- <key>StandardOutPath</key><string>${ log } </string>
54- <key>StandardErrorPath</key><string>${ log } </string>
62+ <key>PATH</key><string>${ plistString ( path ) } </string>
63+ ${ codexHomeXml ? ` ${ codexHomeXml } \n` : "" } </dict>
64+ <key>StandardOutPath</key><string>${ plistString ( log ) } </string>
65+ <key>StandardErrorPath</key><string>${ plistString ( log ) } </string>
5566</dict>
5667</plist>
5768` ;
5869}
5970
71+ function systemdQuote ( value : string ) : string {
72+ return `"${ value
73+ . replace ( / \\ / g, "\\\\" )
74+ . replace ( / " / g, "\\\"" )
75+ . replace ( / % / g, "%%" )
76+ . replace ( / \n / g, "\\n" ) } "`;
77+ }
78+
79+ function systemdEnvironmentAssignment ( name : string , value : string | undefined ) : string | null {
80+ if ( ! value ) return null ;
81+ return `Environment=${ systemdQuote ( `${ name } =${ value } ` ) } ` ;
82+ }
83+
6084function sh ( cmd : string ) : string {
6185 return execSync ( cmd , { encoding : "utf8" , stdio : [ "pipe" , "pipe" , "pipe" ] } ) . trim ( ) ;
6286}
@@ -104,20 +128,25 @@ export function buildUnit(): string {
104128 const { bun, cli } = cliEntry ( ) ;
105129 const log = logPath ( ) ;
106130 const path = process . env . PATH ?? "/usr/local/bin:/usr/bin:/bin" ;
131+ const codexHome = systemdEnvironmentAssignment ( "CODEX_HOME" , process . env . CODEX_HOME ?. trim ( ) ) ;
132+ const envLines = [
133+ systemdEnvironmentAssignment ( "OCX_SERVICE" , "1" ) ,
134+ systemdEnvironmentAssignment ( "PATH" , path ) ,
135+ codexHome ,
136+ ] . filter ( ( line ) : line is string => Boolean ( line ) ) . join ( "\n" ) ;
107137 return `[Unit]
108138Description=OpenCodex Proxy Server
109139After=network-online.target
110140Wants=network-online.target
111141
112142[Service]
113143Type=simple
114- ExecStart=${ bun } ${ cli } start
144+ ExecStart=${ systemdQuote ( bun ) } ${ systemdQuote ( cli ) } start
115145Restart=on-failure
116146RestartSec=5
117- Environment=OCX_SERVICE=1
118- Environment=PATH=${ path }
119- StandardOutput=append:${ log }
120- StandardError=append:${ log }
147+ ${ envLines }
148+ StandardOutput=${ systemdQuote ( `append:${ log } ` ) }
149+ StandardError=${ systemdQuote ( `append:${ log } ` ) }
121150
122151[Install]
123152WantedBy=default.target
0 commit comments