squeezr-ai 1.13.0 → 1.14.0
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/README.md +22 -0
- package/bin/squeezr.js +76 -27
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -564,8 +564,30 @@ The installer configures Squeezr to start automatically on login:
|
|
|
564
564
|
| macOS | launchd (`~/Library/LaunchAgents/com.squeezr.plist`) | Shell auto-heal |
|
|
565
565
|
| Linux | systemd user service (`~/.config/systemd/user/squeezr.service`) | Shell auto-heal |
|
|
566
566
|
| Windows | Task Scheduler (runs at login, restarts on failure) | — |
|
|
567
|
+
| Windows (robust) | **NSSM Windows Service** (auto-restart on crash) | — |
|
|
567
568
|
| **WSL2** | systemd → Task Scheduler (cascade) | Shell auto-heal |
|
|
568
569
|
|
|
570
|
+
### Windows: NSSM (recommended over Task Scheduler)
|
|
571
|
+
|
|
572
|
+
The built-in Task Scheduler setup requires admin on every reinstall and does **not** restart Squeezr if it crashes mid-session (e.g. due to `ECONNRESET`). For a more robust setup, use [NSSM](https://nssm.cc) to run Squeezr as a proper Windows service:
|
|
573
|
+
|
|
574
|
+
```powershell
|
|
575
|
+
# Install NSSM
|
|
576
|
+
winget install nssm
|
|
577
|
+
|
|
578
|
+
# Create the service (run as Administrator, adjust paths if needed)
|
|
579
|
+
$node = (where.exe node | Select-Object -First 1)
|
|
580
|
+
$script = "$(npm root -g)\squeezr-ai\bin\squeezr.js"
|
|
581
|
+
nssm install SqueezrProxy $node $script
|
|
582
|
+
nssm set SqueezrProxy AppExit Default Restart
|
|
583
|
+
nssm set SqueezrProxy AppRestartDelay 3000
|
|
584
|
+
nssm start SqueezrProxy
|
|
585
|
+
```
|
|
586
|
+
|
|
587
|
+
NSSM gives you: auto-start on boot, automatic restart on crash, stdout/stderr logs, and control via `services.msc`.
|
|
588
|
+
|
|
589
|
+
See [NSSM_WINDOWS_SERVICE.md](./NSSM_WINDOWS_SERVICE.md) for the full guide including log setup, troubleshooting, and uninstall steps.
|
|
590
|
+
|
|
569
591
|
### WSL2 support
|
|
570
592
|
|
|
571
593
|
`squeezr setup` detects WSL2 automatically and configures both sides:
|
package/bin/squeezr.js
CHANGED
|
@@ -113,12 +113,23 @@ function stopProxy() {
|
|
|
113
113
|
const match = out.match(/LISTENING\s+(\d+)/)
|
|
114
114
|
pid = match?.[1]
|
|
115
115
|
} else {
|
|
116
|
-
|
|
116
|
+
// Use -sTCP:LISTEN to get only the listening process, not connected clients.
|
|
117
|
+
// lsof may return multiple PIDs without this flag.
|
|
118
|
+
try {
|
|
119
|
+
pid = execSync(`lsof -ti :${port} -sTCP:LISTEN`, { encoding: 'utf-8', stdio: 'pipe' }).trim()
|
|
120
|
+
} catch {
|
|
121
|
+
// fallback: fuser (available on most Linux/WSL)
|
|
122
|
+
try {
|
|
123
|
+
pid = execSync(`fuser ${port}/tcp 2>/dev/null`, { encoding: 'utf-8', stdio: 'pipe' }).trim()
|
|
124
|
+
} catch {}
|
|
125
|
+
}
|
|
117
126
|
}
|
|
118
127
|
if (!pid) {
|
|
119
128
|
console.log(`Squeezr is not running on port ${port}`)
|
|
120
129
|
return
|
|
121
130
|
}
|
|
131
|
+
// Take only the first PID in case multiple are returned
|
|
132
|
+
pid = pid.split(/\s+/)[0]
|
|
122
133
|
if (process.platform === 'win32') {
|
|
123
134
|
execSync(`taskkill /F /PID ${pid}`, { stdio: 'pipe' })
|
|
124
135
|
} else {
|
|
@@ -193,29 +204,65 @@ function setupWindows() {
|
|
|
193
204
|
}
|
|
194
205
|
}
|
|
195
206
|
|
|
196
|
-
// 2.
|
|
197
|
-
|
|
198
|
-
const
|
|
199
|
-
|
|
200
|
-
const ps = [
|
|
201
|
-
`$e = Get-ScheduledTask -TaskName '${taskName}' -ErrorAction SilentlyContinue`,
|
|
202
|
-
`if ($e) { Unregister-ScheduledTask -TaskName '${taskName}' -Confirm:$false }`,
|
|
203
|
-
`$a = New-ScheduledTaskAction -Execute 'powershell.exe' -Argument '-WindowStyle Hidden -NonInteractive -Command "${nodeArg}"' -WorkingDirectory '${ROOT}'`,
|
|
204
|
-
`$t = New-ScheduledTaskTrigger -AtLogon`,
|
|
205
|
-
`$s = New-ScheduledTaskSettingsSet -ExecutionTimeLimit 0 -RestartCount 5 -RestartInterval (New-TimeSpan -Minutes 1)`,
|
|
206
|
-
`Register-ScheduledTask -TaskName '${taskName}' -Action $a -Trigger $t -Settings $s -RunLevel Highest -Force | Out-Null`,
|
|
207
|
-
].join('; ')
|
|
207
|
+
// 2. Auto-start: try NSSM (Windows service, survives crashes) → fallback to Task Scheduler
|
|
208
|
+
const logDir = path.join(os.homedir(), '.squeezr')
|
|
209
|
+
const serviceName = 'SqueezrProxy'
|
|
210
|
+
let autoStartOk = false
|
|
208
211
|
|
|
209
|
-
|
|
210
|
-
execSync(
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
212
|
+
const nssmAvailable = (() => {
|
|
213
|
+
try { execSync('where nssm', { stdio: 'pipe' }); return true } catch { return false }
|
|
214
|
+
})()
|
|
215
|
+
|
|
216
|
+
if (nssmAvailable) {
|
|
217
|
+
try {
|
|
218
|
+
// Remove existing service if present (ignore errors)
|
|
219
|
+
try { execSync(`nssm stop ${serviceName}`, { stdio: 'pipe' }) } catch {}
|
|
220
|
+
try { execSync(`nssm remove ${serviceName} confirm`, { stdio: 'pipe' }) } catch {}
|
|
221
|
+
|
|
222
|
+
execSync(`nssm install ${serviceName} "${nodeExe}" "${distIndex}"`, { stdio: 'pipe' })
|
|
223
|
+
execSync(`nssm set ${serviceName} AppDirectory "${ROOT}"`, { stdio: 'pipe' })
|
|
224
|
+
execSync(`nssm set ${serviceName} AppStdout "${logDir}\\service-stdout.log"`, { stdio: 'pipe' })
|
|
225
|
+
execSync(`nssm set ${serviceName} AppStderr "${logDir}\\service-stderr.log"`, { stdio: 'pipe' })
|
|
226
|
+
execSync(`nssm set ${serviceName} AppRotateFiles 1`, { stdio: 'pipe' })
|
|
227
|
+
execSync(`nssm set ${serviceName} AppRotateSeconds 86400`, { stdio: 'pipe' })
|
|
228
|
+
execSync(`nssm set ${serviceName} AppExit Default Restart`, { stdio: 'pipe' })
|
|
229
|
+
execSync(`nssm set ${serviceName} AppRestartDelay 3000`, { stdio: 'pipe' })
|
|
230
|
+
execSync(`nssm set ${serviceName} Description "Squeezr AI token compression proxy on port 8080"`, { stdio: 'pipe' })
|
|
231
|
+
execSync(`nssm start ${serviceName}`, { stdio: 'pipe' })
|
|
232
|
+
console.log(` [ok] Auto-start registered as Windows service via NSSM (auto-restart on crash)`)
|
|
233
|
+
autoStartOk = true
|
|
234
|
+
} catch (err) {
|
|
235
|
+
const msg = err.stderr?.toString() || err.message || ''
|
|
236
|
+
if (msg.includes('Access') || msg.includes('admin') || msg.includes('5')) {
|
|
237
|
+
console.log(` [warn] NSSM requires admin — run as Administrator for service install`)
|
|
238
|
+
} else {
|
|
239
|
+
console.log(` [warn] NSSM install failed: ${msg.trim().split('\n')[0]}`)
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
if (!autoStartOk) {
|
|
245
|
+
// Fallback: Task Scheduler (no crash recovery, but no admin needed for user tasks)
|
|
246
|
+
const taskName = 'Squeezr'
|
|
247
|
+
const nodeArg = `${nodeExe} \`"${distIndex}\`"`
|
|
248
|
+
const ps = [
|
|
249
|
+
`$e = Get-ScheduledTask -TaskName '${taskName}' -ErrorAction SilentlyContinue`,
|
|
250
|
+
`if ($e) { Unregister-ScheduledTask -TaskName '${taskName}' -Confirm:$false }`,
|
|
251
|
+
`$a = New-ScheduledTaskAction -Execute 'powershell.exe' -Argument '-WindowStyle Hidden -NonInteractive -Command "${nodeArg}"' -WorkingDirectory '${ROOT}'`,
|
|
252
|
+
`$t = New-ScheduledTaskTrigger -AtLogon`,
|
|
253
|
+
`$s = New-ScheduledTaskSettingsSet -ExecutionTimeLimit 0 -RestartCount 5 -RestartInterval (New-TimeSpan -Minutes 1)`,
|
|
254
|
+
`Register-ScheduledTask -TaskName '${taskName}' -Action $a -Trigger $t -Settings $s -RunLevel Highest -Force | Out-Null`,
|
|
255
|
+
].join('; ')
|
|
256
|
+
try {
|
|
257
|
+
execSync(`powershell -NoProfile -Command "${ps}"`, { stdio: 'pipe' })
|
|
258
|
+
console.log(` [ok] Auto-start registered in Task Scheduler (install NSSM for crash recovery)`)
|
|
259
|
+
} catch {
|
|
260
|
+
console.log(` [warn] Auto-start failed — install NSSM or run as admin: https://nssm.cc`)
|
|
261
|
+
}
|
|
214
262
|
}
|
|
215
263
|
|
|
216
264
|
// 3. Start Squeezr right now as a detached background process (no window)
|
|
217
265
|
// Logs go to ~/.squeezr/squeezr.log
|
|
218
|
-
const logDir = path.join(os.homedir(), '.squeezr')
|
|
219
266
|
const logFile = path.join(logDir, 'squeezr.log')
|
|
220
267
|
fs.mkdirSync(logDir, { recursive: true })
|
|
221
268
|
const logFd = fs.openSync(logFile, 'a')
|
|
@@ -261,6 +308,7 @@ function setupUnix() {
|
|
|
261
308
|
`export ANTHROPIC_BASE_URL=http://localhost:${port}`,
|
|
262
309
|
`export openai_base_url=http://localhost:${port}`,
|
|
263
310
|
`export GEMINI_API_BASE_URL=http://localhost:${port}`,
|
|
311
|
+
`# squeezr MITM proxy for Codex (TLS interception)`,
|
|
264
312
|
`export HTTPS_PROXY=http://localhost:${mitmPort}`,
|
|
265
313
|
`export SSL_CERT_FILE=${bundlePath}`,
|
|
266
314
|
`# squeezr auto-heal: start proxy if not running`,
|
|
@@ -281,13 +329,14 @@ function setupUnix() {
|
|
|
281
329
|
fs.appendFileSync(profile, `\n${shellBlock}\n`)
|
|
282
330
|
console.log(` [ok] Env vars + auto-heal added to ${profile}`)
|
|
283
331
|
} else {
|
|
284
|
-
if (!existing.includes('squeezr
|
|
332
|
+
if (!existing.includes('SSL_CERT_FILE') || !existing.includes('squeezr MITM')) {
|
|
333
|
+
// Re-write block to include MITM vars
|
|
285
334
|
const updatedContent = existing.replace(
|
|
286
|
-
/# squeezr env vars\
|
|
335
|
+
/# squeezr env vars[\s\S]*?fi\n/,
|
|
287
336
|
shellBlock + '\n'
|
|
288
337
|
)
|
|
289
338
|
fs.writeFileSync(profile, updatedContent)
|
|
290
|
-
console.log(` [ok]
|
|
339
|
+
console.log(` [ok] Shell profile updated with MITM proxy vars`)
|
|
291
340
|
} else {
|
|
292
341
|
console.log(` [skip] Env vars + auto-heal already in ${profile}`)
|
|
293
342
|
}
|
|
@@ -412,16 +461,16 @@ function setupWSL() {
|
|
|
412
461
|
fs.appendFileSync(profile, `\n${shellBlock}\n`)
|
|
413
462
|
console.log(` [ok] Env vars + auto-heal added to ${profile}`)
|
|
414
463
|
} else {
|
|
415
|
-
// Update existing block
|
|
416
|
-
if (!existing.includes('
|
|
464
|
+
// Update existing block if missing MITM proxy vars
|
|
465
|
+
if (!existing.includes('SSL_CERT_FILE') || !existing.includes('HTTPS_PROXY')) {
|
|
417
466
|
const updatedContent = existing.replace(
|
|
418
|
-
/# squeezr env vars\
|
|
467
|
+
/# squeezr env vars[\s\S]*?fi\n/,
|
|
419
468
|
shellBlock + '\n'
|
|
420
469
|
)
|
|
421
470
|
fs.writeFileSync(profile, updatedContent)
|
|
422
|
-
console.log(` [ok]
|
|
471
|
+
console.log(` [ok] Shell profile updated with MITM proxy vars`)
|
|
423
472
|
} else {
|
|
424
|
-
console.log(` [skip] Env vars
|
|
473
|
+
console.log(` [skip] Env vars already in ${profile}`)
|
|
425
474
|
}
|
|
426
475
|
}
|
|
427
476
|
|
package/dist/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const VERSION = "1.
|
|
1
|
+
export declare const VERSION = "1.14.0";
|
package/dist/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const VERSION = '1.
|
|
1
|
+
export const VERSION = '1.14.0';
|
package/package.json
CHANGED