@xynogen/pix-optimizer 1.0.2 → 1.0.7

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
@@ -6,7 +6,7 @@ shared status-bar cell:
6
6
 
7
7
  - **Caveman** (`⛏`) — terse-output system prompt
8
8
  - **RTK** (`⚔`) — prefixes shell commands with `rtk` + injects RTK prompt
9
- - **TOON** (`✂`) — jq + TOON guidance for dense JSON (+ bundled skill)
9
+ - **TOON** (`✂`) — jq + TOON guidance for dense JSON (skill lives in pix-skills)
10
10
 
11
11
  ## Command
12
12
 
@@ -63,11 +63,14 @@ cargo install rtk-ai
63
63
 
64
64
  ### TOON / JSON Compression (`✂`)
65
65
 
66
- Guidance + a bundled `toon-json` skill for handling information-dense JSON via
67
- `jq` (query/reshape) and `toon` (compress). The system-prompt nudge is injected
68
- **only when the user prompt mentions JSON** (`json`/`jsonl`/`jq`/`toon`/
69
- `openapi`/…). TOON shines on uniform/tabular arrays; deeply nested or
70
- array-of-arrays data and API contracts stay as JSON.
66
+ Guidance for handling information-dense JSON via `jq` (query/reshape) and
67
+ `toon` (compress). The system-prompt nudge is injected **only when the user
68
+ prompt mentions JSON** (`json`/`jsonl`/`jq`/`toon`/`openapi`/…). TOON shines
69
+ on uniform/tabular arrays; deeply nested or array-of-arrays data and API
70
+ contracts stay as JSON.
71
+
72
+ The `toon-json` skill (full workflow + when-NOT-to-use guidance) is bundled in
73
+ `pix-skills` and auto-discovered from there.
71
74
 
72
75
  **Requirement:** `jq` and `toon` on `PATH`.
73
76
 
@@ -90,7 +93,7 @@ pi install npm:@xynogen/pix-optimizer
90
93
  | `src/status.ts` | Shared status-bar cell + `OptimizerHandle` contract |
91
94
  | `src/caveman.ts` | Caveman logic, levels, prompt, settings dialog |
92
95
  | `src/rtk.ts` | RTK prompt + bash command rewriting |
93
- | `src/json.ts` | jq+TOON guidance, heuristics, bundled skill registration |
96
+ | `src/json.ts` | jq+TOON guidance, heuristics, system-prompt injection |
94
97
 
95
98
  Each tool registers its own lifecycle hooks and exposes an `OptimizerHandle`
96
99
  that `/opt` dispatches to. All three share one `OptimizerStatus`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xynogen/pix-optimizer",
3
- "version": "1.0.2",
3
+ "version": "1.0.7",
4
4
  "description": "Performance optimization suite for Pi Coding Agent - caveman mode + RTK tool rewriting + jq/TOON JSON compression",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
package/src/json.test.ts CHANGED
@@ -5,7 +5,6 @@ import {
5
5
  JSON_SYSTEM_PROMPT,
6
6
  mentionsJson,
7
7
  objectDepth,
8
- skillDir,
9
8
  } from "./json.ts";
10
9
 
11
10
  describe("JSON_SYSTEM_PROMPT", () => {
@@ -168,10 +167,3 @@ describe("adviseToon", () => {
168
167
  expect(adviseToon(d2, 2).useToon).toBe(true);
169
168
  });
170
169
  });
171
-
172
- describe("skillDir", () => {
173
- it("points at the bundled toon-json skill", () => {
174
- const dir = skillDir();
175
- expect(dir.endsWith("skills/toon-json")).toBe(true);
176
- });
177
- });
package/src/json.ts CHANGED
@@ -1,12 +1,12 @@
1
1
  /**
2
2
  * json.ts — JSON token-optimization via jq + TOON.
3
3
  *
4
- * Two parts, mirroring rtk.ts/caveman.ts:
5
- * 1. A small system-prompt nudge teaching the model to run JSON through
6
- * `jq` (query/reshape) and `toon` (compress for context), and to convert
7
- * back to JSON only when a strict contract requires it.
8
- * 2. A bundled `toon-json` skill, surfaced via `resources_discover`, that
9
- * holds the full workflow + when-NOT-to-use guidance.
4
+ * A small system-prompt nudge teaching the model to run JSON through
5
+ * `jq` (query/reshape) and `toon` (compress for context), and to convert
6
+ * back to JSON only when a strict contract requires it.
7
+ *
8
+ * The bundled `toon-json` skill lives in pix-skills and is auto-discovered
9
+ * from there — no resources_discover hook needed here.
10
10
  *
11
11
  * TOON = Token-Oriented Object Notation (https://github.com/toon-format/spec).
12
12
  * It shines on uniform/tabular arrays of objects (declare keys once, stream
@@ -17,8 +17,6 @@
17
17
  * by index.ts alongside caveman(pi) and rtk(pi).
18
18
  */
19
19
 
20
- import { join } from "node:path";
21
- import { fileURLToPath } from "node:url";
22
20
  import type {
23
21
  ExtensionAPI,
24
22
  ExtensionCommandContext,
@@ -207,15 +205,6 @@ export function objectDepth(value: unknown): number {
207
205
 
208
206
  // ── Bundled skill path ────────────────────────────────────────────────────────
209
207
 
210
- /**
211
- * Absolute path to the bundled `toon-json` skill directory, resolved relative
212
- * to this module so it works regardless of the extension's install location.
213
- */
214
- export function skillDir(): string {
215
- const here = fileURLToPath(new URL(".", import.meta.url));
216
- return join(here, "skills", "toon-json");
217
- }
218
-
219
208
  // ── Pi extension ──────────────────────────────────────────────────────────────
220
209
 
221
210
  export function json(
@@ -223,10 +212,16 @@ export function json(
223
212
  status: OptimizerStatus,
224
213
  ): OptimizerHandle {
225
214
  let enabled = true;
215
+ let jqAvailable: boolean | null = null;
216
+ let toonAvailable: boolean | null = null;
226
217
 
227
218
  // Report into the shared optimizer indicator.
228
219
  function syncStatus(ctx: Pick<ExtensionContext, "ui">) {
229
- status.set("toon", enabled, ctx);
220
+ status.set(
221
+ "toon",
222
+ enabled && jqAvailable !== false && toonAvailable !== false,
223
+ ctx,
224
+ );
230
225
  }
231
226
 
232
227
  pi.on("session_start", async (_event, ctx) => {
@@ -239,18 +234,38 @@ export function json(
239
234
  syncStatus(ctx);
240
235
  });
241
236
 
242
- // Surface the bundled skill so the model can load the full workflow.
243
- pi.on("resources_discover", async () => {
244
- if (!enabled) return undefined;
245
- return { skillPaths: [skillDir()] };
246
- });
247
-
248
237
  // Inject the JSON-handling nudge into the system prompt, but ONLY when the
249
238
  // user prompt actually mentions JSON / a related token — otherwise it's dead
250
- // weight in every turn.
251
- pi.on("before_agent_start", async (event) => {
239
+ // weight in every turn. Probe jq/toon lazily here (not at session_start) so
240
+ // we don't add startup overhead for a workflow the user may never trigger.
241
+ pi.on("before_agent_start", async (event, ctx) => {
252
242
  if (!enabled) return undefined;
253
243
  if (!mentionsJson(event.prompt)) return undefined;
244
+
245
+ // Probe once on first JSON-relevant prompt.
246
+ if (jqAvailable === null || toonAvailable === null) {
247
+ const [jqRes, toonRes] = await Promise.all([
248
+ pi.exec("which", ["jq"], { timeout: 1000 }).catch(() => ({ code: 1 })),
249
+ pi
250
+ .exec("which", ["toon"], { timeout: 1000 })
251
+ .catch(() => ({ code: 1 })),
252
+ ]);
253
+ jqAvailable = jqRes.code === 0;
254
+ toonAvailable = toonRes.code === 0;
255
+ if (!jqAvailable)
256
+ ctx.ui.notify(
257
+ "jq not found — JSON/TOON guidance disabled. Install: sudo apt install jq or brew install jq",
258
+ "warning",
259
+ );
260
+ if (!toonAvailable)
261
+ ctx.ui.notify(
262
+ "toon not found — JSON/TOON guidance disabled. Install: bun add -g @toon-format/cli or npm i -g @toon-format/cli",
263
+ "warning",
264
+ );
265
+ syncStatus(ctx);
266
+ }
267
+
268
+ if (jqAvailable === false || toonAvailable === false) return undefined;
254
269
  const existing = event.systemPrompt ?? "";
255
270
  return { systemPrompt: `${JSON_SYSTEM_PROMPT}\n\n${existing}` };
256
271
  });
package/src/rtk.ts CHANGED
@@ -286,7 +286,14 @@ export function rtk(
286
286
  // Keep the status indicator in sync across the agent lifecycle. Probe
287
287
  // availability on session start so the icon reflects reality immediately.
288
288
  pi.on("session_start", async (_event, ctx) => {
289
- await checkRtkAvailability();
289
+ const probe = await checkRtkAvailability();
290
+ if (!probe.available && !warnedMissing) {
291
+ ctx.ui.notify(
292
+ "rtk not found — RTK rewriting disabled. Install: cargo install rtk-ai",
293
+ "warning",
294
+ );
295
+ warnedMissing = true;
296
+ }
290
297
  syncStatus(ctx);
291
298
  });
292
299
  pi.on("agent_start", async (_event, ctx) => {
@@ -340,13 +347,6 @@ export function rtk(
340
347
  const probe = await checkRtkAvailability();
341
348
 
342
349
  if (!probe.available) {
343
- if (!warnedMissing) {
344
- ctx.ui.notify(
345
- "RTK binary not found. Install: cargo install rtk-ai",
346
- "warning",
347
- );
348
- warnedMissing = true;
349
- }
350
350
  return undefined; // Don't rewrite if rtk not available
351
351
  }
352
352
 
@@ -1,101 +0,0 @@
1
- ---
2
- name: toon-json
3
- description: Manipulate information-dense JSON efficiently with jq + TOON. Use when fetching/reading large or repetitive JSON (LLM schemas, OpenAPI specs, API responses, datasets, config dumps) into context. Query/reshape with jq, compress to TOON to cut tokens, decode back to JSON only when a strict contract needs it.
4
- ---
5
-
6
- # TOON + jq: Dense JSON Workflow
7
-
8
- ## Goal
9
- Carry only the JSON slice you need, in the cheapest encoding. Query with `jq`,
10
- compress with `toon`, and round-trip back to JSON **only** when a contract
11
- requires strict JSON.
12
-
13
- TOON (Token-Oriented Object Notation, https://github.com/toon-format/spec) is a
14
- line-oriented encoding of the JSON data model. Uniform arrays of objects declare
15
- their keys once and stream bare rows, so token cost drops sharply on tabular and
16
- dense data.
17
-
18
- ## The pipeline
19
-
20
- ```bash
21
- # Fetch → reshape → compress (most common)
22
- curl -s https://api.example.com/models | jq '.data' | toon
23
-
24
- # Local file, show token savings
25
- cat openapi.json | jq '.paths' | toon --stats
26
-
27
- # Just compress, no query
28
- cat data.json | toon
29
-
30
- # Convert TOON back to JSON (strict contract / downstream parser)
31
- echo "$TOON_BLOB" | toon -d
32
- cat data.toon | toon --decode
33
- ```
34
-
35
- `toon` auto-detects direction from input. Force it with `-e` (encode JSON→TOON)
36
- or `-d` (decode TOON→JSON).
37
-
38
- ### Useful flags
39
- - `--stats` — print token/byte statistics for the conversion
40
- - `--delimiter=,|\t|"|"` — array delimiter (comma default; tab/pipe can tokenize better)
41
- - `--keyFolding=safe` — collapse single-key nesting chains
42
- - `--no-strict` — lenient decode
43
-
44
- ## Decide before you compress
45
-
46
- TOON is not always smaller. Pick based on shape:
47
-
48
- | Shape | Action | Why |
49
- |---|---|---|
50
- | Uniform array of objects (same keys, primitive values) | **TOON** | Sweet spot — keys declared once, rows streamed; savings scale with rows × fields |
51
- | Flat object / primitive array | **TOON** | Drops quotes and braces |
52
- | Shallow nesting | **TOON** | Indentation cheaper than braces at low depth |
53
- | Deeply nested / non-uniform | **JSON** | Indentation cost grows; compact JSON can win |
54
- | Array of arrays | **JSON** | TOON's one structurally-worse case (explicit list markers + inner headers) |
55
- | API contract / payload to send or store | **JSON** | Must stay valid JSON for the consumer |
56
-
57
- Rule of thumb: **TOON for reading dense data into context. JSON for contracts.**
58
-
59
- ## When NOT to use TOON
60
- - Anything sent to or stored by an API that expects JSON.
61
- - Data a downstream tool/parser must consume as strict JSON.
62
- - Deeply nested config trees or highly irregular structures.
63
- - Tiny payloads where the conversion overhead isn't worth it.
64
-
65
- In those cases, still use `jq` to slice down to what you need — just skip the
66
- `| toon` step.
67
-
68
- ## Worked examples
69
-
70
- LLM model list (uniform array → great TOON candidate):
71
-
72
- ```bash
73
- curl -s https://api.example.com/v1/models | jq '.data | map({id, owned_by, context})' | toon
74
- ```
75
- ```
76
- [3]{id,owned_by,context}:
77
- gpt-x,acme,128000
78
- gpt-y,acme,200000
79
- gpt-z,acme,1000000
80
- ```
81
-
82
- OpenAPI paths summary (reshape first, then compress):
83
-
84
- ```bash
85
- cat openapi.json \
86
- | jq '[.paths | to_entries[] | {path: .key, methods: (.value | keys)}]' \
87
- | toon --stats
88
- ```
89
-
90
- Round-trip back to JSON for an API call:
91
-
92
- ```bash
93
- RESHAPED=$(cat payload.toon | toon -d)
94
- curl -s -X POST https://api.example.com/ingest -d "$RESHAPED"
95
- ```
96
-
97
- ## Checklist
98
- 1. **Query** — narrow with `jq` to the exact slice needed.
99
- 2. **Decide** — uniform/tabular/shallow → TOON; nested/array-of-arrays/contract → JSON.
100
- 3. **Compress** — `| toon` (add `--stats` to confirm savings).
101
- 4. **Round-trip** — `toon -d` only when strict JSON is required downstream.