squeezr-ai 1.15.0 → 1.16.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.
Files changed (3) hide show
  1. package/README.md +6 -2
  2. package/bin/squeezr.js +114 -12
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -98,7 +98,8 @@ Codex uses WebSocket over TLS to `chatgpt.com` with OAuth authentication — it
98
98
 
99
99
  ```toml
100
100
  [proxy]
101
- port = 8080
101
+ port = 8080 # HTTP proxy (Claude, Aider, Gemini)
102
+ mitm_port = 8081 # MITM proxy (Codex) — defaults to port + 1
102
103
 
103
104
  [compression]
104
105
  threshold = 800 # min chars to trigger compression
@@ -133,7 +134,8 @@ Project-level config is deep-merged over global config. Useful for per-repo tuni
133
134
 
134
135
  | Variable | Default | Description |
135
136
  |----------|---------|-------------|
136
- | `SQUEEZR_PORT` | `8080` | Proxy port (MITM port = this + 1) |
137
+ | `SQUEEZR_PORT` | `8080` | HTTP proxy port (Claude, Aider, Gemini) |
138
+ | `SQUEEZR_MITM_PORT` | `8081` | MITM proxy port (Codex) — defaults to SQUEEZR_PORT + 1 |
137
139
  | `SQUEEZR_THRESHOLD` | `800` | Min chars to compress |
138
140
  | `SQUEEZR_KEEP_RECENT` | `3` | Recent results to skip |
139
141
  | `SQUEEZR_DISABLED` | `false` | Disable all compression |
@@ -172,8 +174,10 @@ squeezr stop # stop the proxy
172
174
  squeezr status # check if proxy is running
173
175
  squeezr logs # show last 50 log lines
174
176
  squeezr config # print current config
177
+ squeezr ports # change HTTP and MITM proxy ports
175
178
  squeezr gain # estimate token savings for a directory
176
179
  squeezr discover # detect which AI CLIs are installed
180
+ squeezr uninstall # remove Squeezr completely (env vars, CA, auto-start, logs)
177
181
  squeezr version # print version
178
182
  ```
179
183
 
package/bin/squeezr.js CHANGED
@@ -42,6 +42,7 @@ Usage:
42
42
  squeezr status Check if proxy is running
43
43
  squeezr config Print config file path and current settings
44
44
  squeezr ports Change HTTP and MITM proxy ports
45
+ squeezr uninstall Remove Squeezr completely (env vars, CA, auto-start, logs)
45
46
  squeezr version Print version
46
47
  squeezr help Show this help
47
48
  `
@@ -66,22 +67,32 @@ async function startDaemon() {
66
67
  process.exit(1)
67
68
  }
68
69
 
69
- // Check if already running
70
+ // Check if already running — and if the version matches
70
71
  const port = process.env.SQUEEZR_PORT || 8080
71
- const running = await new Promise(resolve => {
72
+ const runningVersion = await new Promise(resolve => {
72
73
  const req = http.get(`http://localhost:${port}/squeezr/health`, res => {
73
- resolve(res.statusCode === 200)
74
- res.destroy()
74
+ let data = ''
75
+ res.on('data', chunk => { data += chunk })
76
+ res.on('end', () => {
77
+ try { resolve(JSON.parse(data).version) } catch { resolve('unknown') }
78
+ })
75
79
  })
76
- req.on('error', () => resolve(false))
77
- req.setTimeout(2000, () => { req.destroy(); resolve(false) })
80
+ req.on('error', () => resolve(null))
81
+ req.setTimeout(2000, () => { req.destroy(); resolve(null) })
78
82
  })
79
- if (running) {
80
- const mitmPort = getMitmPort(port)
81
- console.log(`Squeezr is already running`)
82
- console.log(` HTTP proxy (Claude/Aider/Gemini): http://localhost:${port}`)
83
- console.log(` MITM proxy (Codex): http://localhost:${mitmPort}`)
84
- return
83
+ if (runningVersion) {
84
+ if (runningVersion === pkg.version) {
85
+ const mitmPort = getMitmPort(port)
86
+ console.log(`Squeezr is already running (v${pkg.version})`)
87
+ console.log(` HTTP proxy (Claude/Aider/Gemini): http://localhost:${port}`)
88
+ console.log(` MITM proxy (Codex): http://localhost:${mitmPort}`)
89
+ return
90
+ }
91
+ // Version mismatch — old process from before npm update. Kill and restart.
92
+ console.log(`Squeezr v${runningVersion} is running but v${pkg.version} is installed. Restarting...`)
93
+ stopProxy()
94
+ // Wait for ports to free up
95
+ await new Promise(r => setTimeout(r, 1500))
85
96
  }
86
97
 
87
98
  // Launch detached background process
@@ -281,6 +292,94 @@ async function configurePorts() {
281
292
  console.log(` squeezr stop && squeezr start`)
282
293
  }
283
294
 
295
+ // ── squeezr uninstall ─────────────────────────────────────────────────────────
296
+
297
+ async function uninstall() {
298
+ const { createInterface } = await import('readline')
299
+ const rl = createInterface({ input: process.stdin, output: process.stdout })
300
+ const answer = await new Promise(resolve => rl.question(
301
+ 'This will remove Squeezr completely: stop proxy, remove env vars, CA certs, auto-start, config, and logs.\nContinue? [y/N] ', resolve
302
+ ))
303
+ rl.close()
304
+ if (answer.trim().toLowerCase() !== 'y') {
305
+ console.log('Cancelled.')
306
+ return
307
+ }
308
+
309
+ console.log('\nUninstalling Squeezr...\n')
310
+
311
+ // 1. Stop proxy
312
+ stopProxy()
313
+
314
+ // 2. Remove env vars
315
+ if (process.platform === 'win32') {
316
+ const vars = ['ANTHROPIC_BASE_URL', 'GEMINI_API_BASE_URL', 'HTTPS_PROXY', 'NODE_EXTRA_CA_CERTS', 'SQUEEZR_PORT', 'SQUEEZR_MITM_PORT', 'openai_base_url', 'NO_PROXY']
317
+ for (const v of vars) {
318
+ try { execSync(`reg delete "HKCU\\Environment" /v ${v} /f`, { stdio: 'pipe' }) } catch {}
319
+ }
320
+ console.log(' [ok] Windows env vars removed')
321
+ } else {
322
+ // Remove squeezr block from shell profiles
323
+ const profiles = [
324
+ path.join(os.homedir(), '.zshrc'),
325
+ path.join(os.homedir(), '.bashrc'),
326
+ path.join(os.homedir(), '.bash_profile'),
327
+ ]
328
+ for (const p of profiles) {
329
+ try {
330
+ const content = fs.readFileSync(p, 'utf-8')
331
+ if (content.includes('# squeezr env vars')) {
332
+ const cleaned = content.replace(/\n?# squeezr env vars[\s\S]*?fi\n?/g, '\n')
333
+ fs.writeFileSync(p, cleaned)
334
+ console.log(` [ok] Cleaned ${p}`)
335
+ }
336
+ } catch {}
337
+ }
338
+ }
339
+
340
+ // 3. Remove CA from certificate stores
341
+ if (process.platform === 'win32') {
342
+ try { execSync('certutil -delstore -user Root "Squeezr-MITM-CA"', { stdio: 'pipe' }); console.log(' [ok] CA removed from user certificate store') } catch {}
343
+ try { execSync('certutil -delstore Root "Squeezr-MITM-CA"', { stdio: 'pipe' }) } catch {}
344
+ } else if (process.platform === 'darwin') {
345
+ try { execSync('security delete-certificate -c "Squeezr-MITM-CA" ~/Library/Keychains/login.keychain-db', { stdio: 'pipe' }); console.log(' [ok] CA removed from Keychain') } catch {}
346
+ }
347
+ // On Linux, CA is only in bundle.crt which gets deleted with ~/.squeezr below
348
+
349
+ // 4. Remove auto-start
350
+ if (process.platform === 'win32') {
351
+ try { execSync('nssm stop SqueezrProxy', { stdio: 'pipe' }) } catch {}
352
+ try { execSync('nssm remove SqueezrProxy confirm', { stdio: 'pipe' }) } catch {}
353
+ try { execSync('schtasks /Delete /TN "Squeezr" /F', { stdio: 'pipe' }); console.log(' [ok] Removed scheduled task') } catch {}
354
+ } else if (process.platform === 'darwin') {
355
+ const plistPath = path.join(os.homedir(), 'Library', 'LaunchAgents', 'com.squeezr.plist')
356
+ try { execSync(`launchctl unload "${plistPath}"`, { stdio: 'pipe' }) } catch {}
357
+ try { fs.unlinkSync(plistPath); console.log(' [ok] Removed launchd plist') } catch {}
358
+ } else {
359
+ try { execSync('systemctl --user disable --now squeezr', { stdio: 'pipe' }) } catch {}
360
+ const servicePath = path.join(os.homedir(), '.config', 'systemd', 'user', 'squeezr.service')
361
+ try { fs.unlinkSync(servicePath); console.log(' [ok] Removed systemd service') } catch {}
362
+ }
363
+
364
+ // 5. Remove ~/.squeezr (logs, cache, CA, stats)
365
+ const squeezrDir = path.join(os.homedir(), '.squeezr')
366
+ try {
367
+ fs.rmSync(squeezrDir, { recursive: true, force: true })
368
+ console.log(` [ok] Removed ${squeezrDir}`)
369
+ } catch {}
370
+
371
+ // 6. Remove global config
372
+ const tomlPath = path.join(ROOT, 'squeezr.toml')
373
+ try { fs.unlinkSync(tomlPath) } catch {}
374
+
375
+ console.log(`
376
+ Done! Squeezr has been completely removed.
377
+
378
+ To finish, run:
379
+ npm uninstall -g squeezr-ai
380
+ `)
381
+ }
382
+
284
383
  // ── squeezr setup ─────────────────────────────────────────────────────────────
285
384
 
286
385
  function setupWindows() {
@@ -764,6 +863,9 @@ switch (command) {
764
863
  case 'ports':
765
864
  await configurePorts()
766
865
  break
866
+ case 'uninstall':
867
+ await uninstall()
868
+ break
767
869
  case 'config':
768
870
  showConfig()
769
871
  break
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "squeezr-ai",
3
- "version": "1.15.0",
3
+ "version": "1.16.0",
4
4
  "description": "AI proxy that compresses Claude Code, Codex, Aider, Gemini CLI and Ollama context windows to save thousands of tokens per session",
5
5
  "keywords": [
6
6
  "claude",