pi-squeeze 0.2.1 → 0.3.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 CHANGED
@@ -86,9 +86,22 @@ Safety rules:
86
86
  | `/squeeze min <chars>` | smallest output worth compacting (default 400) |
87
87
 
88
88
  Settings are remembered in `<pi agent dir>/squeeze.json` (`PI_CODING_AGENT_DIR`, else `~/.pi/agent`); it also holds
89
- `lineChars`, `perGroup` and `total`, the limits of a compacted result. `PI_SQUEEZE=off` disables it at start.
89
+ `lineChars`, `perGroup` and `total`, the limits of a compacted result, and `logSavings` (below). `PI_SQUEEZE=off` disables it at start.
90
90
  The status line shows the tokens saved.
91
91
 
92
+ ## Savings log
93
+
94
+ Each compacted output adds one line to `<pi agent dir>/squeeze-savings.jsonl`, so the savings can be tracked
95
+ over time; the model never sees it:
96
+
97
+ ```json
98
+ {"ts":"2026-01-02T09:15:00.000Z","session":"…","cwd":"/work/app","tokens":1840,"chars":7360,"kind":"build"}
99
+ ```
100
+
101
+ [tokenburn](https://github.com/sorinirimies/tokenburn) and [pi-tokenburn](https://github.com/sorinirimies/pi-tokenburn)
102
+ read it as the "pi squeeze" saving. When rtk ran the command, rtk logs its own part; this log holds only what
103
+ pi-squeeze cut after it. `"logSavings": false` in `squeeze.json` turns it off.
104
+
92
105
  ## Development
93
106
 
94
107
  ```bash
@@ -14,6 +14,8 @@ export interface Config {
14
14
  enabled: boolean;
15
15
  /** Show the savings in the status line. */
16
16
  showStatus: boolean;
17
+ /** Append each saving to <agent dir>/squeeze-savings.jsonl for usage trackers. */
18
+ logSavings: boolean;
17
19
  /** Which compactors run. */
18
20
  kinds: Record<Kind, boolean>;
19
21
  /** Rewrite commands to their `rtk` form (git, cargo, docker, …) when the rtk binary is installed. */
@@ -31,6 +33,7 @@ export interface Config {
31
33
  export const DEFAULT_CONFIG: Config = {
32
34
  enabled: true,
33
35
  showStatus: true,
36
+ logSavings: true,
34
37
  rtk: true,
35
38
  kinds: Object.fromEntries(KINDS.map((k) => [k, true])) as Record<Kind, boolean>,
36
39
  minChars: 400,
@@ -51,6 +54,7 @@ export function sanitizeConfig(raw: unknown): Config {
51
54
  return {
52
55
  enabled: bool(r.enabled, d.enabled),
53
56
  showStatus: bool(r.showStatus, d.showStatus),
57
+ logSavings: bool(r.logSavings, d.logSavings),
54
58
  rtk: bool(r.rtk, d.rtk),
55
59
  kinds: Object.fromEntries(KINDS.map((kind) => [kind, bool(k[kind], d.kinds[kind])])) as Record<Kind, boolean>,
56
60
  minChars: clampInt(r.minChars, 100, 1_000_000, d.minChars),
@@ -0,0 +1,42 @@
1
+ /**
2
+ * The savings log: one JSON line per compacted output in <agent dir>/squeeze-savings.jsonl, so usage
3
+ * trackers (tokenburn, pi-tokenburn) can count what pi-squeeze saved over time. The model never sees
4
+ * it. When rtk ran the command, rtk logs its own part; this logs only what pi-squeeze cut after it.
5
+ */
6
+ import { appendFile, mkdir } from "node:fs/promises";
7
+ import { homedir } from "node:os";
8
+ import { dirname, join } from "node:path";
9
+ import type { Kind } from "./compact.ts";
10
+ import { resolveAgentDir } from "./config.ts";
11
+
12
+ export const SAVINGS_LOG = "squeeze-savings.jsonl";
13
+
14
+ export const savingsLogPath = (env: Record<string, string | undefined> = process.env, home: string = homedir()): string =>
15
+ join(resolveAgentDir(env, home), SAVINGS_LOG);
16
+
17
+ /** One line of the log. `tokens` is estimated from `chars` (4 characters per token). */
18
+ export interface SavingRecord {
19
+ /** When the output was compacted (ISO 8601, UTC). */
20
+ ts: string;
21
+ session: string;
22
+ cwd: string;
23
+ /** Tokens kept out of the context. */
24
+ tokens: number;
25
+ /** Characters kept out of the context. */
26
+ chars: number;
27
+ /** The compactor that did it. */
28
+ kind: Kind;
29
+ }
30
+
31
+ export const savingLine = (r: SavingRecord): string => JSON.stringify(r) + "\n";
32
+
33
+ /** Appends one record. Never throws: a log that cannot be written must not affect the session. */
34
+ export async function appendSaving(record: SavingRecord, path: string = savingsLogPath()): Promise<boolean> {
35
+ try {
36
+ await mkdir(dirname(path), { recursive: true });
37
+ await appendFile(path, savingLine(record), "utf8");
38
+ return true;
39
+ } catch {
40
+ return false;
41
+ }
42
+ }
@@ -11,6 +11,7 @@ import { completions, parseCommand } from "./command/parse.ts";
11
11
  import { compact, KINDS } from "./core/compact.ts";
12
12
  import { type Config, DEFAULT_CONFIG, optionsOf, readConfig, saveConfig } from "./core/config.ts";
13
13
  import { rewrite } from "./core/rtk.ts";
14
+ import { appendSaving } from "./core/savings.ts";
14
15
  import { fileIn, readFullOutput } from "./core/files.ts";
15
16
  import { saveFull } from "./core/save.ts";
16
17
  import { emptyStats, record, saved, summary, tokens } from "./core/stats.ts";
@@ -68,6 +69,17 @@ export default function (pi: ExtensionAPI) {
68
69
  // Never more than pi would have shown.
69
70
  if (!r || r.text.length >= shown.length) return;
70
71
  record(stats, { ...r, before: shown.length });
72
+ if (config.logSavings) {
73
+ const chars = shown.length - r.after;
74
+ void appendSaving({
75
+ ts: new Date(Date.now()).toISOString(),
76
+ session: ctx.sessionManager?.getSessionId?.() ?? "",
77
+ cwd: ctx.cwd ?? "",
78
+ tokens: tokens(chars),
79
+ chars,
80
+ kind: r.kind,
81
+ });
82
+ }
71
83
  showStatus(ctx);
72
84
  const where = fullPath ?? (r.truncated ? saveFull(original) : undefined);
73
85
  const text = where ? `${r.text}\n[squeeze: output shortened; full output: ${where}]` : r.text;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-squeeze",
3
- "version": "0.2.1",
3
+ "version": "0.3.0",
4
4
  "description": "Shrinks bash output before it reaches the agent's context: native compactors for git, search, listings, tests, builds (cargo, gradle, Maven, javac, Xcode, tsc, docker), Android (adb, lint, detekt), linters, package installs and logs, plus rtk when installed. Full output stays one temp file away.",
5
5
  "keywords": ["pi-package", "pi-extension", "pi", "tokens", "context", "compaction", "rtk"],
6
6
  "license": "MIT",