@xynogen/pix-optimizer 1.1.15 → 1.1.16

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xynogen/pix-optimizer",
3
- "version": "1.1.15",
3
+ "version": "1.1.16",
4
4
  "description": "Performance optimization suite for Pi Coding Agent - caveman mode + RTK tool rewriting + jq/TOON JSON compression + ponytail lazy-dev mode",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
package/src/caveman.ts CHANGED
@@ -108,8 +108,7 @@ export function resolveLevel(arg: string): Level | null {
108
108
  * Help text shown when /caveman is run with no argument.
109
109
  */
110
110
  export function buildHelp(current: Level): string {
111
- const statusLine =
112
- current === "off" ? "off" : `${STATUS_LABELS[current]} (${current})`;
111
+ const statusLine = current === "off" ? "off" : `${STATUS_LABELS[current]} (${current})`;
113
112
  return [
114
113
  `Caveman mode: ${statusLine}`,
115
114
  "",
@@ -133,10 +132,7 @@ export function toggleLevel(current: Level): Level {
133
132
 
134
133
  // ── Pi extension ────────────────────────────────────────────────────────────
135
134
 
136
- export function caveman(
137
- pi: ExtensionAPI,
138
- status: OptimizerStatus,
139
- ): OptimizerHandle {
135
+ export function caveman(pi: ExtensionAPI, status: OptimizerStatus): OptimizerHandle {
140
136
  let level: Level = "off";
141
137
 
142
138
  // -- Status: report into the shared optimizer indicator. --
@@ -179,10 +175,7 @@ export function caveman(
179
175
 
180
176
  // -- Overlay value handler (called by the /optimizer overlay) --
181
177
 
182
- async function run(
183
- value: string,
184
- ctx: ExtensionCommandContext,
185
- ): Promise<void> {
178
+ async function run(value: string, ctx: ExtensionCommandContext): Promise<void> {
186
179
  const resolved = resolveLevel(value);
187
180
  if (resolved === null) return;
188
181
  level = resolved;
@@ -192,9 +185,7 @@ export function caveman(
192
185
  syncStatus(ctx);
193
186
 
194
187
  ctx.ui.notify(
195
- level === "off"
196
- ? "Caveman mode off."
197
- : `Caveman: ${STATUS_LABELS[level]}`,
188
+ level === "off" ? "Caveman mode off." : `Caveman: ${STATUS_LABELS[level]}`,
198
189
  "info",
199
190
  );
200
191
  }
package/src/index.ts CHANGED
@@ -19,11 +19,7 @@ import { json } from "./json.ts";
19
19
  import { registerOptCommand } from "./opt.ts";
20
20
  import { ponytail } from "./ponytail.ts";
21
21
  import { rtk } from "./rtk.ts";
22
- import {
23
- type OptimizerHandle,
24
- OptimizerStatus,
25
- type OptimizerTool,
26
- } from "./status.ts";
22
+ import { type OptimizerHandle, OptimizerStatus, type OptimizerTool } from "./status.ts";
27
23
  import { filterModelWarnings } from "./tool-result-filter.ts";
28
24
 
29
25
  export default function optimizer(pi: ExtensionAPI) {
package/src/json.test.ts CHANGED
@@ -71,9 +71,7 @@ describe("isUniformObjectArray", () => {
71
71
  });
72
72
 
73
73
  it("false for differing keys", () => {
74
- expect(isUniformObjectArray([{ id: 1 }, { id: 2, extra: true }])).toBe(
75
- false,
76
- );
74
+ expect(isUniformObjectArray([{ id: 1 }, { id: 2, extra: true }])).toBe(false);
77
75
  });
78
76
 
79
77
  it("false when a value is itself an object", () => {
package/src/json.ts CHANGED
@@ -182,8 +182,7 @@ export function isUniformObjectArray(arr: unknown[]): boolean {
182
182
  for (let i = 0; i < keys.length; i++) {
183
183
  if (elKeys[i] !== keys[i]) return false;
184
184
  // values must be primitive for a clean tabular row
185
- if (isObjectLike((el as Record<string, unknown>)[keys[i] as string]))
186
- return false;
185
+ if (isObjectLike((el as Record<string, unknown>)[keys[i] as string])) return false;
187
186
  }
188
187
  return true;
189
188
  });
@@ -209,21 +208,14 @@ export function objectDepth(value: unknown): number {
209
208
 
210
209
  // ── Pi extension ──────────────────────────────────────────────────────────────
211
210
 
212
- export function json(
213
- pi: ExtensionAPI,
214
- status: OptimizerStatus,
215
- ): OptimizerHandle {
211
+ export function json(pi: ExtensionAPI, status: OptimizerStatus): OptimizerHandle {
216
212
  let enabled = true;
217
213
  let jqAvailable: boolean | null = null;
218
214
  let toonAvailable: boolean | null = null;
219
215
 
220
216
  // Report into the shared optimizer indicator.
221
217
  function syncStatus(ctx: Pick<ExtensionContext, "ui">) {
222
- status.set(
223
- "toon",
224
- enabled && jqAvailable !== false && toonAvailable !== false,
225
- ctx,
226
- );
218
+ status.set("toon", enabled && jqAvailable !== false && toonAvailable !== false, ctx);
227
219
  }
228
220
 
229
221
  pi.on("session_start", async (_event, ctx) => {
@@ -251,9 +243,7 @@ export function json(
251
243
  if (jqAvailable === null || toonAvailable === null) {
252
244
  const [jqRes, toonRes] = await Promise.all([
253
245
  pi.exec("which", ["jq"], { timeout: 1000 }).catch(() => ({ code: 1 })),
254
- pi
255
- .exec("which", ["toon"], { timeout: 1000 })
256
- .catch(() => ({ code: 1 })),
246
+ pi.exec("which", ["toon"], { timeout: 1000 }).catch(() => ({ code: 1 })),
257
247
  ]);
258
248
  jqAvailable = jqRes.code === 0;
259
249
  toonAvailable = toonRes.code === 0;
@@ -277,10 +267,7 @@ export function json(
277
267
 
278
268
  // -- Overlay value handler (called by the /optimizer overlay) --
279
269
 
280
- async function run(
281
- value: string,
282
- ctx: ExtensionCommandContext,
283
- ): Promise<void> {
270
+ async function run(value: string, ctx: ExtensionCommandContext): Promise<void> {
284
271
  enabled = value === "on";
285
272
  saveOptValue("toon", enabled ? "on" : "off");
286
273
 
package/src/opt.test.ts CHANGED
@@ -4,11 +4,7 @@ import type { OptimizerHandle, OptimizerTool } from "./status.ts";
4
4
 
5
5
  /** Build a handle set with fixed current values + value lists. */
6
6
  function fakeHandles(): Record<OptimizerTool, OptimizerHandle> {
7
- const mk = (
8
- name: OptimizerTool,
9
- current: string,
10
- values: string[],
11
- ): OptimizerHandle => ({
7
+ const mk = (name: OptimizerTool, current: string, values: string[]): OptimizerHandle => ({
12
8
  name,
13
9
  help: `${name} — ${name} help`,
14
10
  values,
package/src/opt.ts CHANGED
@@ -16,11 +16,7 @@
16
16
 
17
17
  import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
18
18
  import { frameLines } from "@xynogen/pix-pretty/modal-frame";
19
- import type {
20
- OptimizerHandle,
21
- OptimizerStatus,
22
- OptimizerTool,
23
- } from "./status.ts";
19
+ import type { OptimizerHandle, OptimizerStatus, OptimizerTool } from "./status.ts";
24
20
  import { toolIcon } from "./status.ts";
25
21
 
26
22
  /** Min/max content width for the overlay box (excludes 4 cols of chrome). */
@@ -28,12 +24,7 @@ const MIN_CONTENT = 28;
28
24
  const MAX_CONTENT = 60;
29
25
 
30
26
  /** Fixed render order — matches the status-bar cell. */
31
- const TOOL_ORDER: readonly OptimizerTool[] = [
32
- "caveman",
33
- "rtk",
34
- "toon",
35
- "ponytail",
36
- ];
27
+ const TOOL_ORDER: readonly OptimizerTool[] = ["caveman", "rtk", "toon", "ponytail"];
37
28
 
38
29
  /** Strip the leading "name [args] — " prefix from a handle's help string. */
39
30
  function helpSummary(help: string): string {
@@ -64,9 +55,7 @@ export function levelBar(current: string, values: readonly string[]): string {
64
55
  }
65
56
 
66
57
  /** Plain-text status fallback when there's no custom-UI host (headless/tests). */
67
- export function buildOptHelp(
68
- handles: Record<OptimizerTool, OptimizerHandle>,
69
- ): string {
58
+ export function buildOptHelp(handles: Record<OptimizerTool, OptimizerHandle>): string {
70
59
  const lines = TOOL_ORDER.map(
71
60
  (n) => ` ${n}: ${handles[n].current()} — ${helpSummary(handles[n].help)}`,
72
61
  );
@@ -140,8 +129,7 @@ export function registerOptCommand(
140
129
  };
141
130
 
142
131
  const move = (direction: -1 | 1) => {
143
- selected =
144
- (selected + direction + TOOL_ORDER.length) % TOOL_ORDER.length;
132
+ selected = (selected + direction + TOOL_ORDER.length) % TOOL_ORDER.length;
145
133
  };
146
134
 
147
135
  return {
@@ -156,14 +144,8 @@ export function registerOptCommand(
156
144
  tool.padEnd(nameWidth),
157
145
  );
158
146
  const cur = handles[tool].current();
159
- const value = theme.fg(
160
- on ? "success" : "dim",
161
- cur.padEnd(valueWidth),
162
- );
163
- const bar = theme.fg(
164
- on ? "accent" : "dim",
165
- levelBar(cur, handles[tool].values),
166
- );
147
+ const value = theme.fg(on ? "success" : "dim", cur.padEnd(valueWidth));
148
+ const bar = theme.fg(on ? "accent" : "dim", levelBar(cur, handles[tool].values));
167
149
  return `${cursor} ${glyph} ${name} ${value} ${bar}`;
168
150
  });
169
151
  const lines = [
@@ -171,12 +153,7 @@ export function registerOptCommand(
171
153
  "",
172
154
  ...rows,
173
155
  "",
174
- theme.fg(
175
- "dim",
176
- helpSummary(
177
- handles[TOOL_ORDER[selected] as OptimizerTool].help,
178
- ),
179
- ),
156
+ theme.fg("dim", helpSummary(handles[TOOL_ORDER[selected] as OptimizerTool].help)),
180
157
  "",
181
158
  theme.fg("dim", "←→ change · ↑↓ move · esc close"),
182
159
  ];
@@ -192,12 +169,7 @@ export function registerOptCommand(
192
169
  if (data === "k" || data === "\u001b[A") move(-1);
193
170
  else if (data === "j" || data === "\u001b[B") move(1);
194
171
  else if (data === "h" || data === "\u001b[D") cycle(-1);
195
- else if (
196
- data === "l" ||
197
- data === "\u001b[C" ||
198
- data === " " ||
199
- data === "\r"
200
- )
172
+ else if (data === "l" || data === "\u001b[C" || data === " " || data === "\r")
201
173
  cycle(1);
202
174
  else if (data === "\u001b" || data === "q") {
203
175
  done(null);
package/src/ponytail.ts CHANGED
@@ -113,8 +113,7 @@ export function resolveLevel(arg: string): Level | null {
113
113
  * Help text shown when /opt ponytail is run with no argument.
114
114
  */
115
115
  export function buildHelp(current: Level): string {
116
- const statusLine =
117
- current === "off" ? "off" : `${STATUS_LABELS[current]} (${current})`;
116
+ const statusLine = current === "off" ? "off" : `${STATUS_LABELS[current]} (${current})`;
118
117
  return [
119
118
  `Ponytail mode: ${statusLine}`,
120
119
  "",
@@ -137,10 +136,7 @@ export function toggleLevel(current: Level): Level {
137
136
 
138
137
  // ── Pi extension ────────────────────────────────────────────────────────────
139
138
 
140
- export function ponytail(
141
- pi: ExtensionAPI,
142
- status: OptimizerStatus,
143
- ): OptimizerHandle {
139
+ export function ponytail(pi: ExtensionAPI, status: OptimizerStatus): OptimizerHandle {
144
140
  let level: Level = "off";
145
141
 
146
142
  // -- Status: report into the shared optimizer indicator. --
@@ -182,10 +178,7 @@ export function ponytail(
182
178
 
183
179
  // -- Overlay value handler (called by the /optimizer overlay) --
184
180
 
185
- async function run(
186
- value: string,
187
- ctx: ExtensionCommandContext,
188
- ): Promise<void> {
181
+ async function run(value: string, ctx: ExtensionCommandContext): Promise<void> {
189
182
  const resolved = resolveLevel(value);
190
183
  if (resolved === null) return;
191
184
  level = resolved;
@@ -195,9 +188,7 @@ export function ponytail(
195
188
  syncStatus(ctx);
196
189
 
197
190
  ctx.ui.notify(
198
- level === "off"
199
- ? "Ponytail mode off."
200
- : `Ponytail: ${STATUS_LABELS[level]}`,
191
+ level === "off" ? "Ponytail mode off." : `Ponytail: ${STATUS_LABELS[level]}`,
201
192
  "info",
202
193
  );
203
194
  }
package/src/rtk.test.ts CHANGED
@@ -19,11 +19,7 @@ describe("splitChain", () => {
19
19
  });
20
20
 
21
21
  it("splits on && keeping operator", () => {
22
- expect(splitChain("git add . && git push")).toEqual([
23
- "git add . ",
24
- "&&",
25
- " git push",
26
- ]);
22
+ expect(splitChain("git add . && git push")).toEqual(["git add . ", "&&", " git push"]);
27
23
  });
28
24
 
29
25
  it("splits on ||, ;, |", () => {
@@ -33,9 +29,7 @@ describe("splitChain", () => {
33
29
  });
34
30
 
35
31
  it("ignores operators inside double quotes", () => {
36
- expect(splitChain('git commit -m "a && b"')).toEqual([
37
- 'git commit -m "a && b"',
38
- ]);
32
+ expect(splitChain('git commit -m "a && b"')).toEqual(['git commit -m "a && b"']);
39
33
  });
40
34
 
41
35
  it("ignores operators inside single quotes", () => {
@@ -59,9 +53,7 @@ describe("rewriteChain", () => {
59
53
  });
60
54
 
61
55
  it("prefixes mixed known commands", () => {
62
- expect(rewriteChain("cargo build && npm test")).toBe(
63
- "rtk cargo build && rtk npm test",
64
- );
56
+ expect(rewriteChain("cargo build && npm test")).toBe("rtk cargo build && rtk npm test");
65
57
  });
66
58
 
67
59
  it("leaves unknown commands alone", () => {
@@ -74,22 +66,16 @@ describe("rewriteChain", () => {
74
66
  });
75
67
 
76
68
  it("only prefixes known segments in a mixed chain", () => {
77
- expect(rewriteChain("cd /tmp && git status")).toBe(
78
- "cd /tmp && rtk git status",
79
- );
69
+ expect(rewriteChain("cd /tmp && git status")).toBe("cd /tmp && rtk git status");
80
70
  });
81
71
 
82
72
  it("does not double-prefix already-rtk commands", () => {
83
73
  expect(rewriteChain("rtk git status")).toBe("rtk git status");
84
- expect(rewriteChain("rtk git add . && git push")).toBe(
85
- "rtk git add . && rtk git push",
86
- );
74
+ expect(rewriteChain("rtk git add . && git push")).toBe("rtk git add . && rtk git push");
87
75
  });
88
76
 
89
77
  it("does not touch operators inside quotes", () => {
90
- expect(rewriteChain('git commit -m "a && b"')).toBe(
91
- 'rtk git commit -m "a && b"',
92
- );
78
+ expect(rewriteChain('git commit -m "a && b"')).toBe('rtk git commit -m "a && b"');
93
79
  });
94
80
 
95
81
  it("returns original on unbalanced quotes", () => {
@@ -106,9 +92,7 @@ describe("rewriteChain", () => {
106
92
  });
107
93
 
108
94
  it("handles pipes between known commands", () => {
109
- expect(rewriteChain("git log | grep fix")).toBe(
110
- "rtk git log | rtk grep fix",
111
- );
95
+ expect(rewriteChain("git log | grep fix")).toBe("rtk git log | rtk grep fix");
112
96
  });
113
97
  });
114
98
 
@@ -120,9 +104,7 @@ describe("detectSudoSegments", () => {
120
104
  });
121
105
 
122
106
  it("detects a plain sudo segment", () => {
123
- expect(detectSudoSegments(["sudo apt-get install foo"])).toEqual([
124
- "sudo apt-get install foo",
125
- ]);
107
+ expect(detectSudoSegments(["sudo apt-get install foo"])).toEqual(["sudo apt-get install foo"]);
126
108
  });
127
109
 
128
110
  it("detects sudo in a chain (operators excluded)", () => {
@@ -132,10 +114,7 @@ describe("detectSudoSegments", () => {
132
114
 
133
115
  it("detects multiple sudo segments", () => {
134
116
  const parts = ["sudo rm -rf /tmp ", ";", " sudo reboot"];
135
- expect(detectSudoSegments(parts)).toEqual([
136
- "sudo rm -rf /tmp",
137
- "sudo reboot",
138
- ]);
117
+ expect(detectSudoSegments(parts)).toEqual(["sudo rm -rf /tmp", "sudo reboot"]);
139
118
  });
140
119
 
141
120
  it("does not match 'sudoer' or 'pseudo'", () => {
@@ -170,10 +149,7 @@ describe("buildSudoBlockReason", () => {
170
149
  });
171
150
 
172
151
  it("lists all blocked commands", () => {
173
- const reason = buildSudoBlockReason(
174
- ["sudo rm -rf /tmp", "sudo reboot"],
175
- true,
176
- );
152
+ const reason = buildSudoBlockReason(["sudo rm -rf /tmp", "sudo reboot"], true);
177
153
  expect(reason).toContain("sudo rm -rf /tmp");
178
154
  expect(reason).toContain("sudo reboot");
179
155
  });
@@ -254,13 +230,9 @@ describe("applyRtkRewrite (tool_call hook step)", () => {
254
230
 
255
231
  it("handles missing / non-string command safely", () => {
256
232
  const event: BashCallEvent = { toolName: "bash", input: {} };
257
- expect(applyRtkRewrite(event, { enabled: true, rtkAvailable: true })).toBe(
258
- false,
259
- );
233
+ expect(applyRtkRewrite(event, { enabled: true, rtkAvailable: true })).toBe(false);
260
234
  const event2: BashCallEvent = { toolName: "bash", input: { command: 123 } };
261
- expect(applyRtkRewrite(event2, { enabled: true, rtkAvailable: true })).toBe(
262
- false,
263
- );
235
+ expect(applyRtkRewrite(event2, { enabled: true, rtkAvailable: true })).toBe(false);
264
236
  });
265
237
 
266
238
  it("leaves command unchanged on unbalanced quotes", () => {
package/src/rtk.ts CHANGED
@@ -51,10 +51,7 @@ export function detectSudoSegments(parts: string[]): string[] {
51
51
  * intercepted. Directs the model to `sudo_run` when available, otherwise
52
52
  * explains the restriction clearly.
53
53
  */
54
- export function buildSudoBlockReason(
55
- sudoCmds: string[],
56
- hasSudoRunTool: boolean,
57
- ): string {
54
+ export function buildSudoBlockReason(sudoCmds: string[], hasSudoRunTool: boolean): string {
58
55
  const list = sudoCmds.map((c) => ` - ${c}`).join("\n");
59
56
  if (hasSudoRunTool) {
60
57
  return (
@@ -224,10 +221,7 @@ export function rewriteChain(command: string): string {
224
221
  return changed ? rewritten.join("") : command;
225
222
  }
226
223
 
227
- export function rtk(
228
- pi: ExtensionAPI,
229
- status: OptimizerStatus,
230
- ): OptimizerHandle {
224
+ export function rtk(pi: ExtensionAPI, status: OptimizerStatus): OptimizerHandle {
231
225
  let rtkStatus: RtkStatus | null = null;
232
226
  let warnedMissing = false;
233
227
  let enabled = true;
@@ -306,10 +300,7 @@ export function rtk(
306
300
 
307
301
  // -- Overlay value handler (called by the /optimizer overlay) --
308
302
 
309
- async function run(
310
- value: string,
311
- ctx: ExtensionCommandContext,
312
- ): Promise<void> {
303
+ async function run(value: string, ctx: ExtensionCommandContext): Promise<void> {
313
304
  enabled = value === "on";
314
305
  saveOptValue("rtk", enabled ? "on" : "off");
315
306
 
@@ -1,10 +1,5 @@
1
1
  import { describe, expect, it } from "bun:test";
2
- import {
3
- OptimizerStatus,
4
- renderStatus,
5
- STATUS_KEY,
6
- toolIcon,
7
- } from "./status.ts";
2
+ import { OptimizerStatus, renderStatus, STATUS_KEY, toolIcon } from "./status.ts";
8
3
 
9
4
  /** Tagging colorizer: <accent>X</accent> / <dim>X</dim> for assertions. */
10
5
  const tag = (c: string, t: string) => `<${c}>${t}</${c}>`;
@@ -17,23 +12,13 @@ const PT = toolIcon("ponytail");
17
12
 
18
13
  describe("renderStatus", () => {
19
14
  it("shows ALL icons in order, accent when enabled", () => {
20
- expect(
21
- renderStatus(
22
- { caveman: true, rtk: true, toon: true, ponytail: true },
23
- tag,
24
- ),
25
- ).toBe(
15
+ expect(renderStatus({ caveman: true, rtk: true, toon: true, ponytail: true }, tag)).toBe(
26
16
  `<accent>${CV}</accent> <accent>${RK}</accent> <accent>${TN}</accent> <accent>${PT}</accent> `,
27
17
  );
28
18
  });
29
19
 
30
20
  it("dims disabled tools but still shows them", () => {
31
- expect(
32
- renderStatus(
33
- { caveman: false, rtk: true, toon: true, ponytail: true },
34
- tag,
35
- ),
36
- ).toBe(
21
+ expect(renderStatus({ caveman: false, rtk: true, toon: true, ponytail: true }, tag)).toBe(
37
22
  `<dim>${CV}</dim> <accent>${RK}</accent> <accent>${TN}</accent> <accent>${PT}</accent> `,
38
23
  );
39
24
  });
@@ -63,8 +48,7 @@ describe("OptimizerStatus", () => {
63
48
  return {
64
49
  calls,
65
50
  ui: {
66
- setStatus: (key: string, text: string | undefined) =>
67
- calls.push({ key, text: text ?? "" }),
51
+ setStatus: (key: string, text: string | undefined) => calls.push({ key, text: text ?? "" }),
68
52
  theme: { fg: (c: string, t: string) => `<${c}>${t}</${c}>` },
69
53
  },
70
54
  } as const;
package/src/status.ts CHANGED
@@ -17,11 +17,7 @@ import type {
17
17
  ExtensionContext,
18
18
  ThemeColor,
19
19
  } from "@earendil-works/pi-coding-agent";
20
- import {
21
- type IconKey,
22
- icon,
23
- onIconModeChange,
24
- } from "@xynogen/pix-pretty/icon-catalog";
20
+ import { type IconKey, icon, onIconModeChange } from "@xynogen/pix-pretty/icon-catalog";
25
21
 
26
22
  /**
27
23
  * Each optimizer tool (caveman/rtk/toon/ponytail) exposes a handle so the
@@ -66,12 +62,7 @@ export function toolIcon(tool: OptimizerTool): string {
66
62
  }
67
63
 
68
64
  /** Fixed left-to-right order of icons in the cell. */
69
- const TOOL_ORDER: readonly OptimizerTool[] = [
70
- "caveman",
71
- "rtk",
72
- "toon",
73
- "ponytail",
74
- ];
65
+ const TOOL_ORDER: readonly OptimizerTool[] = ["caveman", "rtk", "toon", "ponytail"];
75
66
 
76
67
  /** Theme color for enabled icons. */
77
68
  const ENABLED_COLOR: ThemeColor = "accent";
@@ -124,11 +115,7 @@ export class OptimizerStatus {
124
115
  }
125
116
 
126
117
  /** Update one tool's enabled state and repaint the shared cell. */
127
- set(
128
- tool: OptimizerTool,
129
- enabled: boolean,
130
- ctx: Pick<ExtensionContext, "ui">,
131
- ): void {
118
+ set(tool: OptimizerTool, enabled: boolean, ctx: Pick<ExtensionContext, "ui">): void {
132
119
  this.states[tool] = enabled;
133
120
  this.paint(ctx);
134
121
  }
@@ -1,8 +1,5 @@
1
1
  import { describe, expect, it } from "bun:test";
2
- import {
3
- filterModelWarnings,
4
- stripModelWarningParagraphs,
5
- } from "./tool-result-filter.ts";
2
+ import { filterModelWarnings, stripModelWarningParagraphs } from "./tool-result-filter.ts";
6
3
 
7
4
  // ── stripModelWarningParagraphs ───────────────────────────────────────────────
8
5
 
@@ -29,8 +26,7 @@ describe("stripModelWarningParagraphs", () => {
29
26
  });
30
27
 
31
28
  it("strips multiple warning paragraphs", () => {
32
- const text =
33
- "output\n\n⚠ BLIND WRITE — foo\n\n🔴 THRASHING — bar\n\nmore output";
29
+ const text = "output\n\n⚠ BLIND WRITE — foo\n\n🔴 THRASHING — bar\n\nmore output";
34
30
  const result = stripModelWarningParagraphs(text);
35
31
  expect(result).not.toContain("BLIND WRITE");
36
32
  expect(result).not.toContain("THRASHING");
@@ -75,9 +71,7 @@ describe("filterModelWarnings", () => {
75
71
  expect(result).not.toBe(content);
76
72
  expect(result[0]?.type).toBe("text");
77
73
  if (result[0]?.type === "text") {
78
- expect((result[0] as { type: string; text: string }).text).not.toContain(
79
- "BLIND WRITE",
80
- );
74
+ expect((result[0] as { type: string; text: string }).text).not.toContain("BLIND WRITE");
81
75
  }
82
76
  });
83
77
 
@@ -28,10 +28,7 @@ export function stripModelWarningParagraphs(text: string): string {
28
28
  // then rejoin. Trim trailing whitespace from the result.
29
29
  const paragraphs = text.split(/\n\n/);
30
30
  const kept = paragraphs.filter(
31
- (p) =>
32
- !MODEL_WARNING_PREFIXES.some((prefix) =>
33
- p.trimStart().startsWith(prefix),
34
- ),
31
+ (p) => !MODEL_WARNING_PREFIXES.some((prefix) => p.trimStart().startsWith(prefix)),
35
32
  );
36
33
  if (kept.length === paragraphs.length) return text;
37
34
  return kept.join("\n\n").trimEnd();