pi-cc-extensions 0.5.5 → 0.6.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
@@ -4,7 +4,7 @@
4
4
 
5
5
  <p align="center">
6
6
  <a href="#安装"><img alt="Pi package" src="https://img.shields.io/badge/Pi-package-58B7FF?style=flat-square"></a>
7
- <a href="./package.json"><img alt="Version 0.2.0" src="https://img.shields.io/badge/version-0.2.0-66E3C4?style=flat-square"></a>
7
+ <a href="./package.json"><img alt="Version 0.5.6" src="https://img.shields.io/badge/version-0.5.6-66E3C4?style=flat-square"></a>
8
8
  <a href="#兼容性"><img alt="Node.js 22.19 or newer" src="https://img.shields.io/badge/Node.js-%E2%89%A522.19-66E3C4?style=flat-square"></a>
9
9
  <a href="./extensions"><img alt="TypeScript extensions" src="https://img.shields.io/badge/TypeScript-extensions-3178C6?style=flat-square"></a>
10
10
  </p>
@@ -15,10 +15,15 @@
15
15
 
16
16
  ---
17
17
 
18
- ## 截图
18
+ ## 界面预览
19
19
 
20
20
  <table>
21
21
  <tr>
22
+ <td width="50%" align="center">
23
+ <img src="./assets/readme/fixed-editor-navigation.webp" width="100%" alt="Pi fixed-editor 中的工具结果、回到底部按钮与 Ctrl+End 快捷键">
24
+ <br>
25
+ <sub><b>固定编辑器工作流</b><br>工具结果摘要、折叠展开与键盘导航</sub>
26
+ </td>
22
27
  <td width="50%" align="center">
23
28
  <img src="./assets/readme/session-reference.webp" width="100%" alt="在 Pi 中通过 @ 补全选择历史 Session">
24
29
  <br>
@@ -55,9 +60,9 @@
55
60
 
56
61
  ```text
57
62
  /ccstyle # 切换开关
63
+ /ccstyle on # 开启
64
+ /ccstyle off # 关闭
58
65
  /ccstyle status # 查看状态
59
- /ccstyle compact # 紧凑摘要
60
- /ccstyle minimal # 最小化输出
61
66
  ```
62
67
 
63
68
  ### 上下文窗口查看
@@ -82,6 +87,16 @@
82
87
 
83
88
  Session 模糊查询默认显示 5 个候选;若已加载 `pi-subagents`,也可直接引用现有 SubAgent。一次提示词可以引用多个 Session;扩展会自动去重,并限制注入规模以避免上下文无限膨胀。更多细节见 [`extensions/session-reference/README.md`](./extensions/session-reference/README.md)。
84
89
 
90
+ ### SubAgent `@` 补全
91
+
92
+ `extensions/agent-autocomplete.ts` 将 `~/.pi/agent/agents/*.md` 中定义的 SubAgent 接入 `@` 补全:
93
+
94
+ 1. 在提示词中输入 `@agent-name`。
95
+ 2. 从补全列表中选择 SubAgent。
96
+ 3. 提交后自动注入委托指令;提示词中提到的每个 SubAgent 都会分别交由 Agent 工具处理。
97
+
98
+ 该补全不会占用 `@session:` 的历史 Session 引用语法;修改 SubAgent 定义后执行 `/reload` 即可重新加载。
99
+
85
100
  ## 安装
86
101
 
87
102
  从 npm 安装(推荐):
@@ -100,7 +115,7 @@ pi install git:github.com/minuque/pi-cc-extensions
100
115
 
101
116
  ```text
102
117
  /context
103
- /ccstyle status
118
+ /ccstyle on
104
119
  ```
105
120
 
106
121
  ## 本地开发
@@ -126,20 +141,3 @@ pi install /absolute/path/to/pi-cc-extensions
126
141
 
127
142
  - Node.js `>=22.19.0`
128
143
  - 作为 Pi package 加载,入口由根目录 `package.json` 的 `pi.extensions` 显式声明
129
-
130
- ## 发布
131
-
132
- 发布前检查:
133
-
134
- ```bash
135
- npm test
136
- npm pack --dry-run
137
- ```
138
-
139
- 使用 npm 发布。未指定 tag 时使用 `latest`:
140
-
141
- ```bash
142
- npm run release
143
- npm run release -- --tag next
144
- npm run release -- --tag beta
145
- ```
@@ -30,18 +30,13 @@ import { join, resolve } from "node:path";
30
30
  * /ccstyle on enable
31
31
  * /ccstyle off disable
32
32
  * /ccstyle status show current state
33
- * /ccstyle minimal hide most tool output in collapsed view
34
- * /ccstyle compact show short summaries in collapsed view
35
33
  *
36
34
  * Shortcut:
37
35
  * ctrl+shift+o toggle on/off
38
36
  */
39
37
 
40
- type StyleMode = "compact" | "minimal";
41
-
42
38
  type Config = {
43
39
  enabled: boolean;
44
- mode: StyleMode;
45
40
  };
46
41
 
47
42
  const CONFIG_PATH = join(homedir(), ".pi", "agent", "claude-code-style.json");
@@ -54,13 +49,12 @@ function loadConfig(): Config {
54
49
  const parsed = JSON.parse(readFileSync(CONFIG_PATH, "utf8")) as Partial<Config>;
55
50
  return {
56
51
  enabled: parsed.enabled ?? true,
57
- mode: parsed.mode === "minimal" ? "minimal" : "compact",
58
52
  };
59
53
  }
60
54
  } catch {
61
55
  // Ignore bad config and fall back to defaults.
62
56
  }
63
- return { enabled: true, mode: "compact" };
57
+ return { enabled: true };
64
58
  }
65
59
 
66
60
  function saveConfig() {
@@ -318,6 +312,8 @@ const TOOL_MOUSE_WIDGET_KEY = "ccstyle-tool-mouse";
318
312
  const TOOL_MOUSE_ENABLE = "\x1b[?1000h\x1b[?1006h";
319
313
  const TOOL_MOUSE_DISABLE = "\x1b[?1006l\x1b[?1000l";
320
314
  const ZENTUI_PAGE_UP_INPUT = /^\x1b\[5;9(?::[12])?~$|^\x1b\[57421;9(?::[12])?u$|^\x1b\[1;6A$/;
315
+ const ZENTUI_PAGE_DOWN_INPUT = /^\x1b\[6;9(?::[12])?~$|^\x1b\[57422;9(?::[12])?u$|^\x1b\[1;6B$/;
316
+ const SCROLL_BOTTOM_SHORTCUT = "ctrl+end";
321
317
  let toolMouseTui: any = null;
322
318
  let toolMouseUi: any = null;
323
319
  let toolMouseInputUnsubscribe: (() => void) | null = null;
@@ -326,6 +322,9 @@ let toolMouseInputPatchOriginalHandle: ((...args: any[]) => any) | null = null;
326
322
  let toolMouseInputPatchWrapper: ((...args: any[]) => any) | null = null;
327
323
  let scrollButtonVisible = false;
328
324
  let scrollButtonWidget: any = null;
325
+ let pendingScrollMessages = 0;
326
+ let assistantMessageActive = false;
327
+ let scrollButtonSyncScheduled = false;
329
328
 
330
329
  function parseSgrMousePackets(data: string): SgrMousePacket[] | null {
331
330
  const pattern = /\x1b\[<(\d+);(\d+);(\d+)([Mm])/g;
@@ -520,6 +519,96 @@ function isFixedEditorTui(tui: any): boolean {
520
519
  return typeof ownRows?.get === "function" && ownRows.get !== inheritedRows?.get;
521
520
  }
522
521
 
522
+ function formatShortcut(shortcut: string): string {
523
+ return shortcut
524
+ .split("+")
525
+ .map((part) => part.length <= 1 ? part.toUpperCase() : `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`)
526
+ .join("+");
527
+ }
528
+
529
+ function isScrollBottomInput(data: string): boolean {
530
+ return matchesKey(data, SCROLL_BOTTOM_SHORTCUT);
531
+ }
532
+
533
+ function isScrollNavigationInput(data: string): boolean {
534
+ if (
535
+ matchesKey(data, "pageUp")
536
+ || matchesKey(data, "pageDown")
537
+ || ZENTUI_PAGE_UP_INPUT.test(data)
538
+ || ZENTUI_PAGE_DOWN_INPUT.test(data)
539
+ ) {
540
+ return true;
541
+ }
542
+ const packets = parseSgrMousePackets(data);
543
+ return Boolean(packets?.some((packet) => {
544
+ const baseButton = packet.code & ~(4 | 8 | 16 | 32);
545
+ return packet.final === "M" && (baseButton === 64 || baseButton === 65);
546
+ }));
547
+ }
548
+
549
+ function directRenderLines(component: any, width: number): string[] {
550
+ try {
551
+ const lines = component?.render?.(width);
552
+ return Array.isArray(lines) ? lines : [];
553
+ } catch {
554
+ return [];
555
+ }
556
+ }
557
+
558
+ /** Render only the transcript portion that fixed-editor leaves scrollable. */
559
+ function renderFixedScrollableRoot(tui: any, width: number): string[] {
560
+ const children = Array.isArray(tui?.children) ? tui.children : [];
561
+ const editorIndex = children.findIndex((child: any) =>
562
+ containsEditorLike(child, tui.focusedComponent),
563
+ );
564
+ const end = editorIndex >= 2 ? editorIndex - 2 : children.length;
565
+ return children.slice(0, end).flatMap((child: any) => directRenderLines(child, width));
566
+ }
567
+
568
+ function isFixedEditorAtBottom(tui: any): boolean {
569
+ if (!isFixedEditorTui(tui)) return true;
570
+ const visibleLines = Array.isArray(tui?.previousLines) ? tui.previousLines : [];
571
+ if (visibleLines.length === 0) return true;
572
+ const width = Math.max(1, Number(tui?.terminal?.columns) || 80);
573
+ const rootLines = renderFixedScrollableRoot(tui, width);
574
+ if (rootLines.length <= visibleLines.length) return true;
575
+ const tail = rootLines.slice(-visibleLines.length);
576
+ return tail.every((line, index) =>
577
+ stripTerminalSequences(String(line)) === stripTerminalSequences(String(visibleLines[index] ?? "")),
578
+ );
579
+ }
580
+
581
+ function hideScrollButton(tui: any): void {
582
+ const changed = scrollButtonVisible || pendingScrollMessages > 0;
583
+ scrollButtonVisible = false;
584
+ pendingScrollMessages = 0;
585
+ if (changed) tui.requestRender?.();
586
+ }
587
+
588
+ function scheduleScrollButtonSync(tui: any, data: string): void {
589
+ if (!scrollButtonVisible || !isScrollNavigationInput(data) || scrollButtonSyncScheduled) return;
590
+ scrollButtonSyncScheduled = true;
591
+ const previousLines = tui.previousLines;
592
+ const check = (attempt: number) => {
593
+ scrollButtonSyncScheduled = false;
594
+ if (toolMouseTui !== tui || !scrollButtonVisible) return;
595
+ // Pi renders on its own frame timer. Do not inspect the old visible window
596
+ // before Zentui has applied the new scroll offset, or PageUp at bottom would
597
+ // immediately hide the button it just requested.
598
+ const rendered = tui.previousLines !== previousLines;
599
+ if (!rendered && attempt < 4) {
600
+ scrollButtonSyncScheduled = true;
601
+ const timer = setTimeout(() => check(attempt + 1), 16);
602
+ if (typeof timer === "object" && timer !== null && "unref" in timer) {
603
+ (timer as { unref: () => void }).unref();
604
+ }
605
+ return;
606
+ }
607
+ if (isFixedEditorAtBottom(tui)) hideScrollButton(tui);
608
+ };
609
+ process.nextTick(() => check(0));
610
+ }
611
+
523
612
  function updateScrollButtonFromInput(tui: any, data: string): void {
524
613
  if (!isFixedEditorTui(tui)) return;
525
614
 
@@ -532,8 +621,15 @@ function updateScrollButtonFromInput(tui: any, data: string): void {
532
621
  });
533
622
  }
534
623
 
535
- const jumpedBottom = matchesKey(data, "enter") || matchesKey(data, "return");
536
- const nextVisible = jumpedBottom ? false : movedUp ? true : scrollButtonVisible;
624
+ const jumpedBottom =
625
+ matchesKey(data, "enter")
626
+ || matchesKey(data, "return")
627
+ || isScrollBottomInput(data);
628
+ if (jumpedBottom) {
629
+ hideScrollButton(tui);
630
+ return;
631
+ }
632
+ const nextVisible = movedUp ? true : scrollButtonVisible;
537
633
  if (nextVisible !== scrollButtonVisible) {
538
634
  scrollButtonVisible = nextVisible;
539
635
  tui.requestRender?.();
@@ -692,8 +788,7 @@ function jumpToBottomWithoutSubmit(tui: any): boolean {
692
788
  } finally {
693
789
  tui.focusedComponent = focused;
694
790
  }
695
- scrollButtonVisible = false;
696
- tui.requestRender?.();
791
+ hideScrollButton(tui);
697
792
  return true;
698
793
  }
699
794
 
@@ -715,7 +810,11 @@ function toggleToolAtMouseClick(tui: any, packet: SgrMousePacket): boolean {
715
810
 
716
811
  function renderScrollButton(width: number, theme: any): string[] {
717
812
  if (!scrollButtonVisible || !isFixedEditorTui(toolMouseTui)) return [];
718
- const label = theme.fg("accent", "[ ↓ Back to bottom · click ]");
813
+ const shortcut = formatShortcut(SCROLL_BOTTOM_SHORTCUT);
814
+ const messageText = pendingScrollMessages > 0
815
+ ? `${pendingScrollMessages} new message${pendingScrollMessages === 1 ? "" : "s"}`
816
+ : "Back to bottom";
817
+ const label = theme.fg("accent", `[ ↓ ${messageText} · ${shortcut} · click ]`);
719
818
  const leftPad = Math.max(0, Math.floor((width - visibleWidth(label)) / 2));
720
819
  return [`${" ".repeat(leftPad)}${truncateToWidth(label, width, "…")}`];
721
820
  }
@@ -737,6 +836,7 @@ function patchToolMouseInputCapture(tui: any): void {
737
836
  const data = args[0];
738
837
  if (typeof data === "string") {
739
838
  updateScrollButtonFromInput(this, data);
839
+ if (isFixedEditorTui(this) && isScrollBottomInput(data) && jumpToBottomWithoutSubmit(this)) return;
740
840
  const packets = parseSgrMousePackets(data);
741
841
  if (packets) {
742
842
  for (const packet of packets) {
@@ -745,7 +845,9 @@ function patchToolMouseInputCapture(tui: any): void {
745
845
  }
746
846
  }
747
847
  }
748
- return Reflect.apply(originalHandle, this, args);
848
+ const result = Reflect.apply(originalHandle, this, args);
849
+ if (typeof data === "string") scheduleScrollButtonSync(this, data);
850
+ return result;
749
851
  };
750
852
 
751
853
  try {
@@ -774,8 +876,14 @@ function restoreToolMouseInputCapture(): void {
774
876
  function handleToolMouseInput(data: string): { consume: true } | undefined {
775
877
  if (!toolMouseTui) return undefined;
776
878
  updateScrollButtonFromInput(toolMouseTui, data);
879
+ if (isFixedEditorTui(toolMouseTui) && isScrollBottomInput(data) && jumpToBottomWithoutSubmit(toolMouseTui)) {
880
+ return { consume: true };
881
+ }
777
882
  const packets = parseSgrMousePackets(data);
778
- if (!packets) return undefined;
883
+ if (!packets) {
884
+ scheduleScrollButtonSync(toolMouseTui, data);
885
+ return undefined;
886
+ }
779
887
 
780
888
  let consumed = false;
781
889
  for (const packet of packets) {
@@ -787,6 +895,7 @@ function handleToolMouseInput(data: string): { consume: true } | undefined {
787
895
 
788
896
  // Let scrolling, motion, release, and clicks outside tool results reach the
789
897
  // normal TUI input chain (including other extensions such as pi-zentui).
898
+ scheduleScrollButtonSync(toolMouseTui, data);
790
899
  return consumed ? { consume: true } : undefined;
791
900
  }
792
901
 
@@ -806,6 +915,9 @@ function teardownToolMouseInteraction(): void {
806
915
  restoreToolMouseInputCapture();
807
916
  scrollButtonVisible = false;
808
917
  scrollButtonWidget = null;
918
+ pendingScrollMessages = 0;
919
+ assistantMessageActive = false;
920
+ scrollButtonSyncScheduled = false;
809
921
  toolMouseTui = null;
810
922
  toolMouseUi = null;
811
923
  }
@@ -979,7 +1091,7 @@ function renderFileDiffPreview(_toolName: string, _args: any, theme: any, contex
979
1091
  }
980
1092
 
981
1093
  function statusText() {
982
- return config.enabled ? `CC ${config.mode}` : "CC off";
1094
+ return config.enabled ? "CC on" : "CC off";
983
1095
  }
984
1096
 
985
1097
  function updateStatus(ctx: any) {
@@ -1089,14 +1201,7 @@ function createCcstyleTool(originalTool: any): any {
1089
1201
  const expanded = isToolExpanded(options, context);
1090
1202
 
1091
1203
  const text = textFromResult(result);
1092
- let rendered = "";
1093
- if (config.mode === "minimal" && !expanded) {
1094
- rendered = "";
1095
- } else if (!expanded) {
1096
- rendered = text ? oneLine(text, 96) : "Done";
1097
- } else {
1098
- rendered = text;
1099
- }
1204
+ const rendered = !expanded ? (text ? oneLine(text, 96) : "Done") : text;
1100
1205
 
1101
1206
  const hint = !expanded && hasExpandableResult(text) ? expandHint(theme) : "";
1102
1207
  if (expanded) return renderExpandedToolResult(rendered, theme, isError);
@@ -1369,6 +1474,18 @@ function registerWrappedTool(pi: ExtensionAPI, name: keyof ReturnType<typeof cre
1369
1474
  });
1370
1475
  }
1371
1476
 
1477
+ function notePendingScrollMessage(role: unknown): void {
1478
+ if (!toolMouseTui || !isFixedEditorTui(toolMouseTui) || !scrollButtonVisible) return;
1479
+ if (role === "assistant") {
1480
+ if (assistantMessageActive) return;
1481
+ assistantMessageActive = true;
1482
+ } else if (role !== "toolResult") {
1483
+ return;
1484
+ }
1485
+ pendingScrollMessages += 1;
1486
+ toolMouseTui.requestRender?.();
1487
+ }
1488
+
1372
1489
  export default function (pi: ExtensionAPI) {
1373
1490
  installGlobalToolRendering();
1374
1491
  deactivateLegacyCompactionRendering();
@@ -1379,35 +1496,27 @@ export default function (pi: ExtensionAPI) {
1379
1496
  const topLevel = [
1380
1497
  { value: "on", label: "on", description: "Enable Claude Code style" },
1381
1498
  { value: "off", label: "off", description: "Disable Claude Code style" },
1382
- { value: "status", label: "status", description: "Show current toggle and mode" },
1383
- { value: "minimal", label: "minimal", description: "Hide most tool output in collapsed view" },
1384
- { value: "compact", label: "compact", description: "Show short summaries in collapsed view" },
1499
+ { value: "status", label: "status", description: "Show current state" },
1385
1500
  ];
1386
1501
  return topLevel.filter((item) => item.value.startsWith(prefix));
1387
1502
  },
1388
1503
  handler: async (args, ctx) => {
1389
1504
  const arg = args.trim().toLowerCase();
1390
- if (arg === "on" || arg === "enable") config.enabled = true;
1391
- else if (arg === "off" || arg === "disable") config.enabled = false;
1392
- else if (arg === "minimal") {
1393
- config.enabled = true;
1394
- config.mode = "minimal";
1395
- } else if (arg === "compact") {
1396
- config.enabled = true;
1397
- config.mode = "compact";
1398
- } else if (arg === "status") {
1505
+ if (arg === "on") config.enabled = true;
1506
+ else if (arg === "off") config.enabled = false;
1507
+ else if (arg === "status") {
1399
1508
  updateStatus(ctx);
1400
- ctx.ui.notify(
1401
- `Claude Code style: ${config.enabled ? "on" : "off"}, mode=${config.mode}`,
1402
- "info",
1403
- );
1509
+ ctx.ui.notify(`Claude Code style: ${config.enabled ? "on" : "off"}`, "info");
1404
1510
  return;
1405
- } else {
1511
+ } else if (!arg) {
1406
1512
  config.enabled = !config.enabled;
1513
+ } else {
1514
+ ctx.ui.notify("Usage: /ccstyle [on|off|status]", "warning");
1515
+ return;
1407
1516
  }
1408
1517
  saveConfig();
1409
1518
  updateStatus(ctx);
1410
- ctx.ui.notify(`Claude Code style: ${config.enabled ? "on" : "off"}, mode=${config.mode}`, "info");
1519
+ ctx.ui.notify(`Claude Code style: ${config.enabled ? "on" : "off"}`, "info");
1411
1520
  },
1412
1521
  });
1413
1522
 
@@ -1423,10 +1532,24 @@ export default function (pi: ExtensionAPI) {
1423
1532
 
1424
1533
  pi.on("session_start", async (_event, ctx) => {
1425
1534
  diffPreviewByCall.clear();
1535
+ pendingScrollMessages = 0;
1536
+ assistantMessageActive = false;
1426
1537
  updateStatus(ctx);
1427
1538
  installToolMouseInteraction(ctx);
1428
1539
  });
1429
1540
 
1541
+ pi.on("message_start", async (event) => {
1542
+ notePendingScrollMessage(event?.message?.role);
1543
+ });
1544
+
1545
+ pi.on("message_update", async (event) => {
1546
+ if (event?.message?.role === "assistant") notePendingScrollMessage("assistant");
1547
+ });
1548
+
1549
+ pi.on("message_end", async (event) => {
1550
+ if (event?.message?.role === "assistant") assistantMessageActive = false;
1551
+ });
1552
+
1430
1553
  pi.on("session_shutdown", async () => {
1431
1554
  teardownToolMouseInteraction();
1432
1555
  deactivateGlobalToolRendering();
@@ -1440,7 +1563,6 @@ export default function (pi: ExtensionAPI) {
1440
1563
  call: (args) => fileAction(args, "Read"),
1441
1564
  result: (result, { expanded }) => {
1442
1565
  const text = textFromResult(result);
1443
- if (config.mode === "minimal" && !expanded) return "";
1444
1566
  if (!expanded) return `${countLines(text)} lines read`;
1445
1567
  return text;
1446
1568
  },
@@ -1450,7 +1572,6 @@ export default function (pi: ExtensionAPI) {
1450
1572
  call: (args) => `Bash(${oneLine(args?.command, 86) || "..."})`,
1451
1573
  result: (result, { expanded }) => {
1452
1574
  const text = textFromResult(result).trim();
1453
- if (config.mode === "minimal" && !expanded) return "";
1454
1575
  if (!expanded) return summarizeBash(text);
1455
1576
  return text;
1456
1577
  },
@@ -1462,7 +1583,6 @@ export default function (pi: ExtensionAPI) {
1462
1583
  diffAfterResult: true,
1463
1584
  result: (result, { expanded }, _theme, context) => {
1464
1585
  const text = textFromResult(result).trim();
1465
- if (config.mode === "minimal" && !expanded) return "";
1466
1586
  return summarizeDiffStats(context?.state?.ccstyleDiffPreview) ?? summarizeEdit(text);
1467
1587
  },
1468
1588
  });
@@ -1477,7 +1597,6 @@ export default function (pi: ExtensionAPI) {
1477
1597
  diffAfterResult: true,
1478
1598
  result: (result, { expanded }, _theme, context) => {
1479
1599
  const text = textFromResult(result).trim();
1480
- if (config.mode === "minimal" && !expanded) return "";
1481
1600
  return summarizeDiffStats(context?.state?.ccstyleDiffPreview) ?? (text ? oneLine(text, 96) : "Written");
1482
1601
  },
1483
1602
  });
@@ -1486,7 +1605,6 @@ export default function (pi: ExtensionAPI) {
1486
1605
  call: (args) => `Find(${args?.pattern || "..."}${args?.path ? ` in ${shortenPath(args.path)}` : ""})`,
1487
1606
  result: (result, { expanded }) => {
1488
1607
  const text = textFromResult(result).trim();
1489
- if (config.mode === "minimal" && !expanded) return "";
1490
1608
  if (!expanded) return `${countLines(text)} files`;
1491
1609
  return text;
1492
1610
  },
@@ -1496,7 +1614,6 @@ export default function (pi: ExtensionAPI) {
1496
1614
  call: (args) => `Grep(${args?.pattern ? `/${oneLine(args.pattern, 48)}/` : "..."})`,
1497
1615
  result: (result, { expanded }) => {
1498
1616
  const text = textFromResult(result).trim();
1499
- if (config.mode === "minimal" && !expanded) return "";
1500
1617
  if (!expanded) {
1501
1618
  const matches = countLines(text);
1502
1619
  const files = parsePathCount(text);
@@ -1510,7 +1627,6 @@ export default function (pi: ExtensionAPI) {
1510
1627
  call: (args) => `List(${shortenPath(args?.path || ".")})`,
1511
1628
  result: (result, { expanded }) => {
1512
1629
  const text = textFromResult(result).trim();
1513
- if (config.mode === "minimal" && !expanded) return "";
1514
1630
  if (!expanded) return `${countLines(text)} entries`;
1515
1631
  return text;
1516
1632
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-cc-extensions",
3
- "version": "0.5.5",
3
+ "version": "0.6.0",
4
4
  "description": "Personal extensions for the Pi coding agent",
5
5
  "type": "module",
6
6
  "keywords": [