squeezr-ai 1.10.4 → 1.10.6
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 +2 -0
- package/bin/squeezr.js +30 -1
- package/dist/gain.js +17 -8
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -103,6 +103,8 @@ localhost:8080 (Squeezr proxy)
|
|
|
103
103
|
Your provider's API (Anthropic / OpenAI / Google / Ollama)
|
|
104
104
|
```
|
|
105
105
|
|
|
106
|
+
**MCP tool results are compressed automatically.** Any tool result that passes through the proxy — including results from MCP servers (Linear, GitHub, Slack, planning tools, custom MCPs) — goes through the same compression pipeline. No configuration needed; Squeezr treats MCP tool results identically to built-in tools. In practice MCP responses are often large JSON payloads that compress 70-94%.
|
|
107
|
+
|
|
106
108
|
Recent content is always preserved untouched — by default the last 3 tool results are never compressed. Your CLI always has full context for what it's currently working on.
|
|
107
109
|
|
|
108
110
|
---
|
package/bin/squeezr.js
CHANGED
|
@@ -24,6 +24,7 @@ Usage:
|
|
|
24
24
|
squeezr start Start the proxy
|
|
25
25
|
squeezr setup One-time setup: auto-start on login + configure all CLIs
|
|
26
26
|
squeezr stop Stop the running proxy
|
|
27
|
+
squeezr logs Show last 50 lines of the log file
|
|
27
28
|
squeezr gain Show token savings stats
|
|
28
29
|
squeezr gain --reset Reset saved stats
|
|
29
30
|
squeezr discover Show pattern coverage report (proxy must be running)
|
|
@@ -46,6 +47,23 @@ function runNode(script, extraArgs = []) {
|
|
|
46
47
|
child.on('exit', code => process.exit(code ?? 0))
|
|
47
48
|
}
|
|
48
49
|
|
|
50
|
+
function showLogs() {
|
|
51
|
+
const logFile = path.join(os.homedir(), '.squeezr', 'squeezr.log')
|
|
52
|
+
if (!fs.existsSync(logFile)) {
|
|
53
|
+
console.log('No log file yet. Run: squeezr setup')
|
|
54
|
+
return
|
|
55
|
+
}
|
|
56
|
+
// Show last 50 lines
|
|
57
|
+
const lines = fs.readFileSync(logFile, 'utf-8').split('\n').filter(Boolean)
|
|
58
|
+
const tail = lines.slice(-50)
|
|
59
|
+
if (tail.length === 0) {
|
|
60
|
+
console.log('Log file is empty — no requests yet.')
|
|
61
|
+
return
|
|
62
|
+
}
|
|
63
|
+
console.log(`=== ${logFile} (last ${tail.length} lines) ===\n`)
|
|
64
|
+
console.log(tail.join('\n'))
|
|
65
|
+
}
|
|
66
|
+
|
|
49
67
|
function stopProxy() {
|
|
50
68
|
const port = process.env.SQUEEZR_PORT || 8080
|
|
51
69
|
try {
|
|
@@ -156,14 +174,21 @@ function setupWindows() {
|
|
|
156
174
|
}
|
|
157
175
|
|
|
158
176
|
// 3. Start Squeezr right now as a detached background process (no window)
|
|
177
|
+
// Logs go to ~/.squeezr/squeezr.log
|
|
178
|
+
const logDir = path.join(os.homedir(), '.squeezr')
|
|
179
|
+
const logFile = path.join(logDir, 'squeezr.log')
|
|
180
|
+
fs.mkdirSync(logDir, { recursive: true })
|
|
181
|
+
const logFd = fs.openSync(logFile, 'a')
|
|
159
182
|
const child = spawn(nodeExe, [distIndex], {
|
|
160
183
|
detached: true,
|
|
161
|
-
stdio: 'ignore',
|
|
184
|
+
stdio: ['ignore', logFd, logFd],
|
|
162
185
|
windowsHide: true,
|
|
163
186
|
cwd: ROOT,
|
|
164
187
|
})
|
|
165
188
|
child.unref()
|
|
189
|
+
fs.closeSync(logFd)
|
|
166
190
|
console.log(` [ok] Squeezr started in background (pid ${child.pid})`)
|
|
191
|
+
console.log(` [ok] Logs → ${logFile}`)
|
|
167
192
|
|
|
168
193
|
console.log(`
|
|
169
194
|
Done!
|
|
@@ -292,6 +317,10 @@ switch (command) {
|
|
|
292
317
|
stopProxy()
|
|
293
318
|
break
|
|
294
319
|
|
|
320
|
+
case 'logs':
|
|
321
|
+
showLogs()
|
|
322
|
+
break
|
|
323
|
+
|
|
295
324
|
case 'gain':
|
|
296
325
|
runNode('gain.js', args.slice(1))
|
|
297
326
|
break
|
package/dist/gain.js
CHANGED
|
@@ -27,21 +27,30 @@ const savedChars = data.total_saved_chars;
|
|
|
27
27
|
const originalChars = data.total_original_chars;
|
|
28
28
|
const CHARS_PER_TOKEN = 3.5;
|
|
29
29
|
const savedTokens = Math.round(savedChars / CHARS_PER_TOKEN);
|
|
30
|
-
const pct = originalChars > 0 ? Math.round((savedChars / originalChars) * 1000) / 10 : 0;
|
|
31
30
|
const byTool = (data.by_tool ?? {});
|
|
31
|
+
// Savings % on tool results only (what Squeezr actually compresses).
|
|
32
|
+
// Using total context chars gives a misleadingly low number because the
|
|
33
|
+
// denominator includes user messages, Claude responses, and history
|
|
34
|
+
// re-sent on every request — none of which Squeezr touches.
|
|
35
|
+
const toolOriginal = Object.values(byTool).reduce((s, d) => s + d.originalChars, 0);
|
|
36
|
+
const toolSaved = Object.values(byTool).reduce((s, d) => s + d.savedChars, 0);
|
|
37
|
+
const toolPct = toolOriginal > 0 ? Math.round((toolSaved / toolOriginal) * 1000) / 10 : 0;
|
|
38
|
+
// Context reduction: how much smaller the overall payload became
|
|
39
|
+
const ctxPct = originalChars > 0 ? Math.round((savedChars / originalChars) * 1000) / 10 : 0;
|
|
32
40
|
console.log('┌─────────────────────────────────────────┐');
|
|
33
41
|
console.log('│ Squeezr — Token Savings │');
|
|
34
42
|
console.log('├─────────────────────────────────────────┤');
|
|
35
|
-
console.log(`│ Requests
|
|
36
|
-
console.log(`│ Saved chars
|
|
37
|
-
console.log(`│ Saved tokens
|
|
38
|
-
console.log(`│
|
|
43
|
+
console.log(`│ Requests ${String(requests).padEnd(23)}│`);
|
|
44
|
+
console.log(`│ Saved chars ${String(savedChars.toLocaleString()).padEnd(23)}│`);
|
|
45
|
+
console.log(`│ Saved tokens ${String(savedTokens.toLocaleString()).padEnd(23)}│`);
|
|
46
|
+
console.log(`│ Tool savings ${String(`${toolPct}%`).padEnd(23)}│`);
|
|
47
|
+
console.log(`│ Context reduction ${String(`${ctxPct}%`).padEnd(22)}│`);
|
|
39
48
|
if (Object.keys(byTool).length > 0) {
|
|
40
49
|
console.log('├─────────────────────────────────────────┤');
|
|
41
50
|
console.log('│ By Tool │');
|
|
42
|
-
for (const [tool, d] of Object.entries(byTool)) {
|
|
43
|
-
const
|
|
44
|
-
const line = ` ${tool} (${d.count}x): -${
|
|
51
|
+
for (const [tool, d] of Object.entries(byTool).sort((a, b) => b[1].savedChars - a[1].savedChars)) {
|
|
52
|
+
const pct = d.originalChars > 0 ? Math.round((d.savedChars / d.originalChars) * 1000) / 10 : 0;
|
|
53
|
+
const line = ` ${tool} (${d.count}x): -${pct}%`;
|
|
45
54
|
console.log(`│${line.padEnd(41)}│`);
|
|
46
55
|
}
|
|
47
56
|
}
|
package/dist/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const VERSION = "1.10.
|
|
1
|
+
export declare const VERSION = "1.10.6";
|
package/dist/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const VERSION = '1.10.
|
|
1
|
+
export const VERSION = '1.10.6';
|
package/package.json
CHANGED