@xynogen/pix-edit 0.1.12 → 0.1.14

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-edit",
3
- "version": "0.1.12",
3
+ "version": "0.1.14",
4
4
  "description": "Pi tool — precise text replacement edit with diff rendering",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
@@ -34,7 +34,7 @@
34
34
  "access": "public"
35
35
  },
36
36
  "dependencies": {
37
- "@xynogen/pix-pretty": "^1.7.9",
37
+ "@xynogen/pix-pretty": "^1.7.20",
38
38
  "@xynogen/pix-data": "^0.3.0"
39
39
  },
40
40
  "peerDependencies": {
package/src/edit.test.ts CHANGED
@@ -1,11 +1,7 @@
1
1
  import { describe, expect, it } from "bun:test";
2
2
  import type { CursorStore, FffState } from "@xynogen/pix-pretty/fff";
3
3
  import type { PiPrettyApi, TextComponentCtor } from "@xynogen/pix-pretty/types";
4
- import {
5
- getEditOperations,
6
- registerEditTool,
7
- summarizeEditOperations,
8
- } from "./edit";
4
+ import { getEditOperations, registerEditTool, summarizeEditOperations } from "./edit";
9
5
 
10
6
  class MockTextComponent {
11
7
  private text = "";
@@ -72,9 +68,7 @@ describe("getEditOperations", () => {
72
68
 
73
69
  describe("summarizeEditOperations", () => {
74
70
  it("returns a summary string", () => {
75
- const { summary } = summarizeEditOperations([
76
- { oldText: "a\nb", newText: "c\nd\ne" },
77
- ]);
71
+ const { summary } = summarizeEditOperations([{ oldText: "a\nb", newText: "c\nd\ne" }]);
78
72
  expect(typeof summary).toBe("string");
79
73
  expect(summary.length).toBeGreaterThan(0);
80
74
  });
package/src/edit.ts CHANGED
@@ -30,7 +30,9 @@ import type {
30
30
  import {
31
31
  fillToolBackground,
32
32
  getTextContent,
33
+ hideCollapsedToolCall,
33
34
  isTextContent,
35
+ renderCollapsedToolRow,
34
36
  renderToolError,
35
37
  setResultDetails,
36
38
  termW,
@@ -167,14 +169,16 @@ export function registerEditTool(
167
169
  return result;
168
170
  },
169
171
 
170
- renderCall(
171
- args: EditParams,
172
- theme: ThemeLike,
173
- renderCtx: RenderContextLike<EditRenderState>,
174
- ) {
172
+ renderCall(args: EditParams, theme: ThemeLike, renderCtx: RenderContextLike<EditRenderState>) {
175
173
  const fp = args?.path ?? args?.file_path ?? "";
176
174
  const operations = getEditOperations(args);
177
175
  const text = renderCtx.lastComponent ?? new TextComponent("", 0, 0);
176
+ if (
177
+ hideCollapsedToolCall(renderCtx.state as CollapseState, renderCtx.expanded, (value) =>
178
+ text.setText(value),
179
+ )
180
+ )
181
+ return text;
178
182
  const hdr = `${theme.fg("toolTitle", theme.bold("edit"))} ${theme.fg("accent", sp(fp))}`;
179
183
 
180
184
  if (operations.length === 0) {
@@ -183,10 +187,7 @@ export function registerEditTool(
183
187
  }
184
188
 
185
189
  const { summary } = summarizeEditOperations(operations);
186
- const suffix =
187
- operations.length === 1
188
- ? summary
189
- : `${operations.length} edits ${summary}`;
190
+ const suffix = operations.length === 1 ? summary : `${operations.length} edits ${summary}`;
190
191
  text.setText(fillToolBackground(`${hdr} ${theme.fg("muted", suffix)}`));
191
192
  return text;
192
193
  },
@@ -211,23 +212,26 @@ export function registerEditTool(
211
212
  d?._type === "editInfo"
212
213
  ? (d.summary as string)
213
214
  : d?._type === "multiEditInfo"
214
- ? `${d.editCount} edits ${d.summary}`
215
+ ? `${d.editCount} edits · ${d.summary}`
215
216
  : "edited";
216
- text.setText(fillToolBackground(` ${theme.fg("muted", summary)}`));
217
+ let filePath = "";
218
+ if (d?._type === "editInfo") filePath = String(d.filePath ?? "");
219
+ else if (d?._type === "multiEditInfo") {
220
+ const ops = d.ops as Array<Record<string, unknown>> | undefined;
221
+ filePath = String(ops?.[0]?.filePath ?? "");
222
+ }
223
+ text.setText(renderCollapsedToolRow(theme, "edit", sp(filePath), summary));
217
224
  return text;
218
225
  }
219
226
 
220
227
  // Single edit — full split diff
221
228
  if (d?._type === "editInfo") {
222
229
  const key = `ed:${diffThemeCacheKey(theme)}:${termW()}:${d.summary}:${(d.oldContent as string).length}:${(d.newContent as string).length}:${d.language ?? ""}`;
223
- if (renderCtx.toolCallId)
224
- trackInvalidator(renderCtx.toolCallId, renderCtx.invalidate);
230
+ if (renderCtx.toolCallId) trackInvalidator(renderCtx.toolCallId, renderCtx.invalidate);
225
231
  if (renderCtx.state._edk !== key) {
226
232
  renderCtx.state._edk = key;
227
233
  const loc =
228
- (d.editLine as number) > 0
229
- ? ` ${theme.fg("muted", `at line ${d.editLine}`)}`
230
- : "";
234
+ (d.editLine as number) > 0 ? ` ${theme.fg("muted", `at line ${d.editLine}`)}` : "";
231
235
  renderCtx.state._edt = ` ${d.summary}${loc}\n${theme.fg("muted", " rendering diff…")}`;
232
236
  const dc = resolveDiffColors(theme);
233
237
  const diff = parseDiff(
@@ -236,18 +240,11 @@ export function registerEditTool(
236
240
  3,
237
241
  d.editLine as number,
238
242
  );
239
- renderSplit(
240
- diff,
241
- d.language as string | undefined,
242
- MAX_RENDER_LINES,
243
- dc,
244
- )
243
+ renderSplit(diff, d.language as string | undefined, MAX_RENDER_LINES, dc)
245
244
  .then((rendered) => {
246
245
  if (renderCtx.state._edk !== key) return;
247
246
  const loc2 =
248
- (d.editLine as number) > 0
249
- ? ` ${theme.fg("muted", `at line ${d.editLine}`)}`
250
- : "";
247
+ (d.editLine as number) > 0 ? ` ${theme.fg("muted", `at line ${d.editLine}`)}` : "";
251
248
  renderCtx.state._edt = ` ${d.summary}${loc2}\n${rendered}`;
252
249
  renderCtx.invalidate();
253
250
  })
@@ -264,8 +261,7 @@ export function registerEditTool(
264
261
  // Multi-edit — stacked diffs
265
262
  if (d?._type === "multiEditInfo") {
266
263
  const key = `med:${diffThemeCacheKey(theme)}:${termW()}:${d.summary}:${d.editCount}:${d.diffLineCount}`;
267
- if (renderCtx.toolCallId)
268
- trackInvalidator(renderCtx.toolCallId, renderCtx.invalidate);
264
+ if (renderCtx.toolCallId) trackInvalidator(renderCtx.toolCallId, renderCtx.invalidate);
269
265
  if (renderCtx.state._edk !== key) {
270
266
  renderCtx.state._edk = key;
271
267
  renderCtx.state._edt = ` ${d.editCount} edits ${d.summary}\n${theme.fg("muted", " rendering diff…")}`;
@@ -279,12 +275,7 @@ export function registerEditTool(
279
275
  editLine?: number;
280
276
  }>
281
277
  ).map((op) => {
282
- const diff = parseDiff(
283
- op.oldContent,
284
- op.newContent,
285
- 3,
286
- op.editLine ?? 0,
287
- );
278
+ const diff = parseDiff(op.oldContent, op.newContent, 3, op.editLine ?? 0);
288
279
  return renderSplit(diff, op.language, MAX_RENDER_LINES, dc);
289
280
  }),
290
281
  )
@@ -300,20 +291,13 @@ export function registerEditTool(
300
291
  renderCtx.invalidate();
301
292
  });
302
293
  }
303
- text.setText(
304
- renderCtx.state._edt ?? ` ${d.editCount} edits ${d.summary}`,
305
- );
294
+ text.setText(renderCtx.state._edt ?? ` ${d.editCount} edits ${d.summary}`);
306
295
  return text;
307
296
  }
308
297
 
309
298
  const fallback = result.content?.[0];
310
- const fallbackText =
311
- fallback && isTextContent(fallback) ? fallback.text : "edited";
312
- text.setText(
313
- fillToolBackground(
314
- ` ${theme.fg("dim", String(fallbackText).slice(0, 120))}`,
315
- ),
316
- );
299
+ const fallbackText = fallback && isTextContent(fallback) ? fallback.text : "edited";
300
+ text.setText(fillToolBackground(` ${theme.fg("dim", String(fallbackText).slice(0, 120))}`));
317
301
  return text;
318
302
  },
319
303
  });
package/src/extension.ts CHANGED
@@ -4,15 +4,8 @@ import {
4
4
  type EditToolInput,
5
5
  } from "@earendil-works/pi-coding-agent";
6
6
  import { CursorStore, fffState } from "@xynogen/pix-pretty/fff";
7
- import {
8
- attachResizeListener,
9
- trackInvalidator,
10
- } from "@xynogen/pix-pretty/resize";
11
- import type {
12
- PiPrettyApi,
13
- TextComponentCtor,
14
- ToolFactory,
15
- } from "@xynogen/pix-pretty/types";
7
+ import { attachResizeListener, trackInvalidator } from "@xynogen/pix-pretty/resize";
8
+ import type { PiPrettyApi, TextComponentCtor, ToolFactory } from "@xynogen/pix-pretty/types";
16
9
  import { shortPath } from "@xynogen/pix-pretty/utils";
17
10
  import { registerEditTool } from "./edit.js";
18
11
  import { once } from "./once.ts";