pi-cc-extensions 0.8.53 → 0.8.54

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.
Files changed (39) hide show
  1. package/README.en.md +6 -8
  2. package/README.md +5 -6
  3. package/assets/readme/hero.en.svg +101 -0
  4. package/extensions/config/config.ts +1 -17
  5. package/extensions/config/panel.ts +5 -3
  6. package/extensions/{utils/agent-summary.ts → feature/agent-summary/core.ts} +37 -35
  7. package/extensions/feature/{agent-summary.ts → agent-summary/index.ts} +2 -6
  8. package/extensions/feature/{session-reference.ts → reference/index.ts} +1 -1
  9. package/extensions/feature/{pi-startup-header.ts → shell/startup-header.ts} +1 -1
  10. package/extensions/index.ts +22 -33
  11. package/extensions/renderer/compact-mode.ts +371 -84
  12. package/extensions/renderer/default-mode.ts +726 -0
  13. package/extensions/renderer/index.ts +57 -773
  14. package/extensions/renderer/{mouse-hover.ts → mouse/hover.ts} +5 -5
  15. package/extensions/renderer/{mouse-interaction.ts → mouse/interaction.ts} +37 -35
  16. package/extensions/renderer/{mouse-layout.ts → mouse/layout.ts} +5 -21
  17. package/extensions/renderer/{mouse-packets.ts → mouse/packets.ts} +1 -1
  18. package/extensions/renderer/{mouse-scroll.ts → mouse/scroll.ts} +46 -33
  19. package/extensions/renderer/{tool-diff → tool/diff}/diff-renderer.ts +2 -2
  20. package/extensions/renderer/{tool-diff → tool/diff}/line-width-safety.ts +1 -1
  21. package/extensions/renderer/tool/diff/write-display-utils.ts +12 -0
  22. package/extensions/renderer/{tool-grouping.ts → tool/grouping.ts} +18 -8
  23. package/extensions/renderer/{tool-result.ts → tool/result.ts} +4 -13
  24. package/extensions/utils/fullscreen-detect.ts +0 -27
  25. package/package.json +3 -2
  26. package/extensions/renderer/tool-diff/write-display-utils.ts +0 -29
  27. /package/extensions/feature/{session-reference-core.ts → reference/session.ts} +0 -0
  28. /package/extensions/feature/{agent-autocomplete.ts → reference/subagent.ts} +0 -0
  29. /package/extensions/feature/{pi-aliases.ts → shell/aliases.ts} +0 -0
  30. /package/extensions/feature/{working-message.ts → shell/working-message.ts} +0 -0
  31. /package/extensions/{feature → renderer}/markdown-enhance.ts +0 -0
  32. /package/extensions/renderer/{tool-diff → tool/diff}/ATTRIBUTION.md +0 -0
  33. /package/extensions/renderer/{tool-diff → tool/diff}/ansi-utils.ts +0 -0
  34. /package/extensions/renderer/{tool-diff → tool/diff}/diff-presentation.ts +0 -0
  35. /package/extensions/renderer/{tool-diff → tool/diff}/index.ts +0 -0
  36. /package/extensions/renderer/{tool-diff → tool/diff}/render-utils.ts +0 -0
  37. /package/extensions/renderer/{tool-diff → tool/diff}/shiki-highlight.ts +0 -0
  38. /package/extensions/renderer/{tool-diff → tool/diff}/types.ts +0 -0
  39. /package/extensions/renderer/{tool-diff → tool/diff}/write-execution.ts +0 -0
package/README.en.md CHANGED
@@ -1,5 +1,5 @@
1
1
  <p align="center">
2
- <img src="./assets/readme/hero.svg" width="100%" alt="pi-cc-extensions: a productivity extension suite for Pi">
2
+ <img src="./assets/readme/hero.en.svg" width="100%" alt="pi-cc-extensions: a productivity extension suite for Pi">
3
3
  </p>
4
4
 
5
5
  <p align="center">
@@ -10,7 +10,7 @@
10
10
  </p>
11
11
 
12
12
  <p align="center">
13
- Claude Code-style output, context inspection, and Agent / Session references.
13
+ Claude Code-style TUI output with some personal touches and handy utilities.
14
14
  </p>
15
15
 
16
16
  <p align="center">
@@ -41,11 +41,11 @@ Run `/reload` after installation.
41
41
 
42
42
  | Feature | Description | Entry point |
43
43
  | ------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
44
- | Claude Code-style output | Tool summaries, expand/collapse, rich edit/write diffs, and`on` / `compact` / `off` modes | `/ccstyle` |
45
- | Fullscreen mouse interaction | Tool card/group click-to-toggle, previews, hover highlight, and a back-to-bottom button | `TUIMODE=fullscreen` or `--tui-mode fullscreen` |
44
+ | Claude Code Output | Tool summaries, expand/collapse, rich edit/write diffs, and`on` / `compact` / `off` modes | `/ccstyle` |
45
+ | Fullscreen mode | Tool card/group click-to-toggle, previews, hover highlight, and a back-to-bottom button | `TUIMODE=fullscreen` or `--tui-mode fullscreen` |
46
46
  | Settings panel | `Style / Diff / Thinking / Feature` tabs: startup header toggle and wheel step | `/ccstyle` |
47
47
  | Context inspection | Usage breakdown and previews for the system prompt, tools, skills, and messages | `/context` |
48
- | Session references | Search and inject effective context from previous Sessions or existing SubAgents | `@session:` |
48
+ | Session/Subagent references | Search and inject effective context from previous Sessions or existing SubAgents | `@` |
49
49
  | Theme | Bundled CC Dark and CC Light themes | `/theme` |
50
50
 
51
51
  ## Configuration
@@ -78,8 +78,6 @@ npm run typecheck
78
78
  ./test.bat # or pi -e .
79
79
  ```
80
80
 
81
- Run `/reload` after changing extensions.
82
-
83
81
  ## Compatibility
84
82
 
85
83
  - Node.js `>=22.19.0`, Pi `^0.84.0` (loaded through `pi.extensions` and `pi.themes` in the root `package.json`)
@@ -100,4 +98,4 @@ Run `/reload` after changing extensions.
100
98
 
101
99
  ## Credits
102
100
 
103
- - Rich diffs are adapted from [`MasuRii/pi-tool-display`](https://github.com/MasuRii/pi-tool-display) (MIT). See [`extensions/tool-diff/ATTRIBUTION.md`](./extensions/tool-diff/ATTRIBUTION.md).
101
+ - Rich diffs are adapted from [`MasuRii/pi-tool-display`](https://github.com/MasuRii/pi-tool-display) (MIT). See [`extensions/renderer/tool/diff/ATTRIBUTION.md`](./extensions/renderer/tool/diff/ATTRIBUTION.md).
package/README.md CHANGED
@@ -10,7 +10,7 @@
10
10
  </p>
11
11
 
12
12
  <p align="center">
13
- 类 Claude Code TUI 输出风格、上下文检查,以及 Agent / Session 引用。
13
+ 类 Claude Code TUI 输出风格,并融入了一些个人喜好,和一些实用小功能。
14
14
  </p>
15
15
 
16
16
  <p align="center">
@@ -41,11 +41,11 @@ pi install git:github.com/minuque/pi-cc-extensions
41
41
 
42
42
  | 功能 | 说明 | 入口 |
43
43
  | ---------------------- | ---------------------------------------------------------------------------------------------------------- | ------------- |
44
- | Claude Code 风格输出 | 工具摘要、折叠展开、rich edit/write diff,以及`on` / `compact` / `off` 三种模式 | `/ccstyle` |
45
- | Fullscreen 鼠标交互 | 工具卡/group 点击展开与收起、预览、hover 高亮、回到底部按钮 | `TUIMODE=fullscreen` 或 `--tui-mode fullscreen` |
44
+ | Claude Code UI | 工具摘要、折叠展开、rich edit/write diff,以及`on` / `compact` / `off` 三种模式 | `/ccstyle` |
45
+ | Fullscreen mode | 工具卡/group 点击展开与收起、预览、hover 高亮、回到底部按钮 | `TUIMODE=fullscreen` 或 `--tui-mode fullscreen` |
46
46
  | 配置面板 | `Style / Diff / Thinking / Feature` 四页签,含启动头开关与滚轮步进 | `/ccstyle` |
47
47
  | 上下文检查 | 查看上下文占用,并预览 System prompt、Tools、Skills 和消息内容 | `/context` |
48
- | Session 引用 | 搜索并注入历史 Session 或现有 SubAgent 的有效上下文 | `@session:` |
48
+ | Session/Subagent 引用 | 搜索并注入历史 Session 或现有 SubAgent 的有效上下文 | `@` |
49
49
  | 主题 | 随包提供内置 CC Dark、CC Light 主题 | `/theme` |
50
50
 
51
51
  ## 配置
@@ -78,7 +78,6 @@ npm run typecheck
78
78
  ./test.bat # or pi -e .
79
79
  ```
80
80
 
81
- 修改扩展后执行 `/reload`。
82
81
 
83
82
  ## 兼容性
84
83
 
@@ -100,4 +99,4 @@ npm run typecheck
100
99
 
101
100
  ## 致谢
102
101
 
103
- - Rich diff 改编自 [`MasuRii/pi-tool-display`](https://github.com/MasuRii/pi-tool-display)(MIT);详见 [`extensions/tool-diff/ATTRIBUTION.md`](./extensions/tool-diff/ATTRIBUTION.md)。
102
+ - Rich diff 改编自 [`MasuRii/pi-tool-display`](https://github.com/MasuRii/pi-tool-display)(MIT);详见 [`extensions/renderer/tool/diff/ATTRIBUTION.md`](./extensions/renderer/tool/diff/ATTRIBUTION.md)。
@@ -0,0 +1,101 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="1200" height="400" viewBox="0 0 1200 400" role="img" aria-labelledby="title desc">
2
+ <title id="title">pi-cc-extensions
3
+ </title>
4
+ <desc id="desc">The Claude and Pi brand marks together connect three extension capabilities: Claude Code-style output, context inspection, and historical Session references.
5
+ </desc>
6
+ <defs>
7
+ <linearGradient id="panel" x1="0" y1="0" x2="1" y2="1">
8
+ <stop offset="0" stop-color="#0D131B"/>
9
+ <stop offset="1" stop-color="#090D12"/>
10
+ </linearGradient>
11
+ </defs>
12
+ <rect width="1200" height="400" rx="28" fill="url(#panel)"/>
13
+ <rect x="1" y="1" width="1198" height="398" rx="27" fill="none" stroke="#263241" stroke-width="2"/>
14
+ <g id="title-block" transform="translate(64 58)" font-family="-apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', sans-serif">
15
+ <g font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" font-size="16" font-weight="600" letter-spacing="1.4">
16
+ <text x="0" y="0" fill="#66E3C4">PI EXTENSION
17
+ </text>
18
+ </g>
19
+ <text x="0" y="82" fill="#F4F7FA" font-size="54" font-weight="750" letter-spacing="-1.5">pi-cc-extensions
20
+ </text>
21
+ <text x="0" y="130" fill="#B8C3CF" font-size="23">Make Pi work like Claude Code 🙃
22
+ </text>
23
+ <g transform="translate(0 180)" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" font-size="17">
24
+ <rect width="488" height="58" rx="12" fill="#111923" stroke="#2B3948"/>
25
+ <text x="20" y="36" fill="#66E3C4">›
26
+ </text>
27
+ <text x="44" y="36" fill="#F4F7FA">/ccstyle
28
+ </text>
29
+ <text x="155" y="36" fill="#536172">·
30
+ </text>
31
+ <text x="178" y="36" fill="#7CC7FF">/context
32
+ </text>
33
+ <text x="292" y="36" fill="#536172">·
34
+ </text>
35
+ <text x="315" y="36" fill="#F2C879">@session:
36
+ </text>
37
+ <rect x="411" y="22" width="9" height="20" rx="2" fill="#66E3C4"/>
38
+ </g>
39
+ <g transform="translate(0 282)" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" font-size="15">
40
+ <circle cx="6" cy="-5" r="6" fill="#66E3C4"/>
41
+ <text x="22" y="0" fill="#8B9AAD">3 EXTENSIONS
42
+ </text>
43
+ <text x="160" y="0" fill="#3B4857">•
44
+ </text>
45
+ <text x="183" y="0" fill="#8B9AAD">TYPESCRIPT
46
+ </text>
47
+ <text x="303" y="0" fill="#3B4857">•
48
+ </text>
49
+ <text x="326" y="0" fill="#8B9AAD">NODE ≥ 22.19
50
+ </text>
51
+ </g>
52
+ </g>
53
+ <g id="extension-map" transform="translate(662 48)" font-family="-apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', sans-serif">
54
+ <g id="claude-pi-mark" transform="translate(0 0)">
55
+ <!-- Official Claude starburst vector; source: Anthropic Claude brand mark. -->
56
+ <path transform="translate(2 2) scale(.34)" fill="#D97757" d="m19.6 66.5 19.7-11 .3-1-.3-.5h-1l-3.3-.2-11.2-.3L14 53l-9.5-.5-2.4-.5L0 49l.2-1.5 2-1.3 2.9.2 6.3.5 9.5.6 6.9.4L38 49.1h1.6l.2-.7-.5-.4-.4-.4L29 41l-10.6-7-5.6-4.1-3-2-1.5-2-.6-4.2 2.7-3 3.7.3.9.2 3.7 2.9 8 6.1L37 36l1.5 1.2.6-.4.1-.3-.7-1.1L33 25l-6-10.4-2.7-4.3-.7-2.6c-.3-1-.4-2-.4-3l3-4.2L28 0l4.2.6L33.8 2l2.6 6 4.1 9.3L47 29.9l2 3.8 1 3.4.3 1h.7v-.5l.5-7.2 1-8.7 1-11.2.3-3.2 1.6-3.8 3-2L61 2.6l2 2.9-.3 1.8-1.1 7.7L59 27.1l-1.5 8.2h.9l1-1.1 4.1-5.4 6.9-8.6 3-3.5L77 13l2.3-1.8h4.3l3.1 4.7-1.4 4.9-4.4 5.6-3.7 4.7-5.3 7.1-3.2 5.7.3.4h.7l12-2.6 6.4-1.1 7.6-1.3 3.5 1.6.4 1.6-1.4 3.4-8.2 2-9.6 2-14.3 3.3-.2.1.2.3 6.4.6 2.8.2h6.8l12.6 1 3.3 2 1.9 2.7-.3 2-5.1 2.6-6.8-1.6-16-3.8-5.4-1.3h-.8v.4l4.6 4.5 8.3 7.5L89 80.1l.5 2.4-1.3 2-1.4-.2-9.2-7-3.6-3-8-6.8h-.5v.7l1.8 2.7 9.8 14.7.5 4.5-.7 1.4-2.6 1-2.7-.6-5.8-8-6-9-4.7-8.2-.5.4-2.9 30.2-1.3 1.5-3 1.2-2.5-2-1.4-3 1.4-6.2 1.6-8 1.3-6.4 1.2-7.9.7-2.6v-.2H49L43 72l-9 12.3-7.2 7.6-1.7.7-3-1.5.3-2.8L24 86l10-12.8 6-7.9 4-4.6-.1-.5h-.3L17.2 77.4l-4.7.6-2-2 .2-3 1-1 8-5.5Z"/>
57
+ <path d="M50 3V35" stroke="#3A4857" stroke-width="2"/>
58
+ <!-- Official Pi logo vectors; source: https://pi.dev/logo-auto.svg -->
59
+ <g transform="translate(52 -5) scale(.06)" fill="#F4F7FA">
60
+ <path fill-rule="evenodd" d="M165.29 165.29H517.36V400H400V517.36H282.65V634.72H165.29ZM282.65 282.65V400H400V282.65Z"/>
61
+ <path d="M517.36 400H634.72V634.72H517.36Z"/>
62
+ </g>
63
+ <text x="104" y="15" fill="#F4F7FA" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" font-size="15" font-weight="700" letter-spacing=".8">CLAUDE CODE UX
64
+ </text>
65
+ <text x="104" y="34" fill="#7F8D9C" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" font-size="13" letter-spacing="1.2">FOR PI
66
+ </text>
67
+ </g>
68
+ <g transform="translate(0 52)">
69
+ <rect width="474" height="82" rx="14" fill="#101821" stroke="#2C3A48"/>
70
+ <rect width="5" height="82" rx="2.5" fill="#66E3C4"/>
71
+ <text x="26" y="32" fill="#F4F7FA" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" font-size="18" font-weight="700">/ccstyle
72
+ </text>
73
+ <text x="26" y="59" fill="#8B9AAD" font-size="16">Tool summaries · Diffs · Status bar
74
+ </text>
75
+ <circle cx="438" cy="29" r="9" fill="#66E3C4" opacity=".18"/>
76
+ <path d="M434 29l3 3 6-7" fill="none" stroke="#66E3C4" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
77
+ </g>
78
+ <g transform="translate(0 144)">
79
+ <rect width="474" height="82" rx="14" fill="#101821" stroke="#2C3A48"/>
80
+ <rect width="5" height="82" rx="2.5" fill="#7CC7FF"/>
81
+ <text x="26" y="32" fill="#F4F7FA" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" font-size="18" font-weight="700">/context
82
+ </text>
83
+ <text x="26" y="59" fill="#8B9AAD" font-size="16">Usage breakdown · Injected content preview
84
+ </text>
85
+ <g transform="translate(416 23)">
86
+ <rect width="42" height="14" rx="7" fill="#1C2B38"/>
87
+ <rect width="27" height="14" rx="7" fill="#7CC7FF"/>
88
+ </g>
89
+ </g>
90
+ <g transform="translate(0 236)">
91
+ <rect width="474" height="82" rx="14" fill="#101821" stroke="#2C3A48"/>
92
+ <rect width="5" height="82" rx="2.5" fill="#F2C879"/>
93
+ <text x="26" y="32" fill="#F4F7FA" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" font-size="18" font-weight="700">@session:
94
+ </text>
95
+ <text x="26" y="59" fill="#8B9AAD" font-size="16">History completion · Cross-session references
96
+ </text>
97
+ <text x="431" y="40" fill="#F2C879" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" font-size="26">@
98
+ </text>
99
+ </g>
100
+ </g>
101
+ </svg>
@@ -4,7 +4,7 @@ import {
4
4
  type DiffIndicatorMode,
5
5
  type DiffViewMode,
6
6
  type ToolDisplayConfig,
7
- } from "../renderer/tool-diff/index.ts";
7
+ } from "../renderer/tool/diff/index.ts";
8
8
  import { existsSync, readFileSync, writeFileSync } from "node:fs";
9
9
  import { homedir } from "node:os";
10
10
  import { join } from "node:path";
@@ -86,22 +86,6 @@ export function pickPositiveNumber(value: unknown, fallback: number, min = 1): n
86
86
  return Number.isFinite(n) ? Math.max(min, n) : fallback;
87
87
  }
88
88
 
89
- export function nearestPreset(value: number, presets: readonly string[]): string {
90
- const numeric = presets.map((p) => Number(p));
91
- let best = presets[0] ?? String(value);
92
- let bestDist = Number.POSITIVE_INFINITY;
93
- for (let i = 0; i < numeric.length; i++) {
94
- const dist = Math.abs((numeric[i] ?? 0) - value);
95
- if (dist < bestDist) {
96
- bestDist = dist;
97
- best = presets[i] ?? best;
98
- }
99
- }
100
- // Prefer exact match when value is already a preset.
101
- const exact = presets.find((p) => Number(p) === value);
102
- return exact ?? best;
103
- }
104
-
105
89
  export function normalizeConfig(input: unknown): Config {
106
90
  const source = (input && typeof input === "object" ? input : {}) as Record<string, unknown>;
107
91
  const mode = source.mode;
@@ -7,9 +7,9 @@
7
7
  import { getSettingsListTheme } from "@earendil-works/pi-coding-agent";
8
8
  import { Input, SettingsList, matchesKey, truncateToWidth } from "@earendil-works/pi-tui";
9
9
  import type { CompactThinkingController } from "../feature/compact-thinking.ts";
10
- import { applyStartupHeader } from "../feature/pi-startup-header.ts";
11
- import type { ToolGroupingHooks } from "../renderer/tool-grouping.ts";
12
- import type { DiffIndicatorMode, DiffViewMode } from "../renderer/tool-diff/index.ts";
10
+ import { applyStartupHeader } from "../feature/shell/startup-header.ts";
11
+ import type { ToolGroupingHooks } from "../renderer/tool/grouping.ts";
12
+ import type { DiffIndicatorMode, DiffViewMode } from "../renderer/tool/diff/index.ts";
13
13
  import {
14
14
  config,
15
15
  DEFAULT_CONFIG,
@@ -553,4 +553,6 @@ export async function showCcstylePanel(
553
553
  },
554
554
  };
555
555
  });
556
+ // 面板卸下后主 transcript 重新挂载;再刷一次,吃掉打开期间扫树失败的切换。
557
+ hooks.refreshCurrentTranscript(ctx, toolGrouping);
556
558
  }
@@ -1,26 +1,24 @@
1
1
  /**
2
2
  * Agent 回合摘要:统计一次 agent 运行的工具使用并格式化成摘要文本。
3
3
  *
4
- * 统计口径参考已删除的 compact-style(ea64df0 "sunset fixed-editor and compact
5
- * mode"):read 按文件去重、edit/write 按文件去重、bash 计命令数、其余工具计数、
6
- * 失败计数、回合耗时。与旧实现一致,`read`/`edit`/`write` 只认精确的工具名
7
- * (MCP 风格 `server__read` 归入 other)。
4
+ * 分类:bash / read / edit / write / other(精确工具名;MCP 风格名归 other)。
5
+ * 计数:bash 按调用次数;read/edit/write 按非空 path/file_path 去重;other 按调用次数。
6
+ * 失败单独累计;另记回合耗时。
8
7
  *
9
- * 呈现:`summaryLine` 输出纯文本(旧格式),`summaryMarkdown` 输出 Markdown
10
- * 增强版——加粗统计词,box 模式包 `> [!TIP]` 提示框(由 markdown-enhance 渲染
11
- * 成带图标的表格框),供当前 Markdown 渲染管线使用。
8
+ * 呈现:`summaryLine` 纯文本,`summaryMarkdown` Markdown(可 box 引用块)。
12
9
  */
13
10
 
14
11
  import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
15
12
 
16
- /** 工具分类,与旧 compact-style 统计口径一致。 */
17
- export type AgentToolCategory = "read" | "edit" | "bash" | "other";
13
+ /** 工具分类。 */
14
+ export type AgentToolCategory = "bash" | "read" | "edit" | "write" | "other";
18
15
 
19
16
  /** 一次 agent 回合的统计快照。 */
20
17
  export type AgentSummaryData = {
18
+ commands: number;
21
19
  reads: number;
22
20
  edits: number;
23
- commands: number;
21
+ writes: number;
24
22
  others: number;
25
23
  failed: number;
26
24
  durationMs: number;
@@ -28,9 +26,10 @@ export type AgentSummaryData = {
28
26
 
29
27
  export function classifyTool(toolName: string): AgentToolCategory {
30
28
  const base = toolName.split(".").pop() ?? toolName;
31
- if (base === "read") return "read";
32
- if (base === "edit" || base === "write") return "edit";
33
29
  if (base === "bash") return "bash";
30
+ if (base === "read") return "read";
31
+ if (base === "edit") return "edit";
32
+ if (base === "write") return "write";
34
33
  return "other";
35
34
  }
36
35
 
@@ -38,12 +37,18 @@ function nonEmptyString(value: unknown): value is string {
38
37
  return typeof value === "string" && value.length > 0;
39
38
  }
40
39
 
40
+ function toolPath(args?: Record<string, unknown> | null): string | undefined {
41
+ const path = args?.path ?? args?.file_path;
42
+ return nonEmptyString(path) ? path : undefined;
43
+ }
44
+
41
45
  /** 累积一次 agent 回合的工具统计;agent_start 时新建实例。 */
42
46
  export class AgentRunSummary {
43
47
  toolCount = 0;
48
+ commandCount = 0;
44
49
  readFiles = new Set<string>();
45
50
  editFiles = new Set<string>();
46
- commandCount = 0;
51
+ writeFiles = new Set<string>();
47
52
  otherCount = 0;
48
53
  failedCount = 0;
49
54
 
@@ -56,16 +61,19 @@ export class AgentRunSummary {
56
61
  /** tool_execution_start 时调用。 */
57
62
  recordToolStart(toolName: string, args?: Record<string, unknown> | null): void {
58
63
  this.toolCount++;
59
- const path = args?.path ?? args?.file_path;
64
+ const path = toolPath(args);
60
65
  switch (classifyTool(toolName)) {
66
+ case "bash":
67
+ this.commandCount++;
68
+ break;
61
69
  case "read":
62
- if (nonEmptyString(path)) this.readFiles.add(path);
70
+ if (path) this.readFiles.add(path);
63
71
  break;
64
72
  case "edit":
65
- if (nonEmptyString(path)) this.editFiles.add(path);
73
+ if (path) this.editFiles.add(path);
66
74
  break;
67
- case "bash":
68
- this.commandCount++;
75
+ case "write":
76
+ if (path) this.writeFiles.add(path);
69
77
  break;
70
78
  default:
71
79
  this.otherCount++;
@@ -79,9 +87,10 @@ export class AgentRunSummary {
79
87
 
80
88
  snapshot(now = Date.now()): AgentSummaryData {
81
89
  return {
90
+ commands: this.commandCount,
82
91
  reads: this.readFiles.size,
83
92
  edits: this.editFiles.size,
84
- commands: this.commandCount,
93
+ writes: this.writeFiles.size,
85
94
  others: this.otherCount,
86
95
  failed: this.failedCount,
87
96
  durationMs: now - this.startedAt,
@@ -103,17 +112,19 @@ export function formatDuration(ms: number): string {
103
112
 
104
113
  const plural = (count: number) => (count === 1 ? "" : "s");
105
114
 
115
+ /** 输出顺序:bash → read → edit → write → other → failed。 */
106
116
  function summaryParts(data: AgentSummaryData): string[] {
107
117
  const parts: string[] = [];
118
+ if (data.commands) parts.push(`ran ${data.commands} command${plural(data.commands)}`);
108
119
  if (data.reads) parts.push(`read ${data.reads} file${plural(data.reads)}`);
109
120
  if (data.edits) parts.push(`edited ${data.edits} file${plural(data.edits)}`);
121
+ if (data.writes) parts.push(`wrote ${data.writes} file${plural(data.writes)}`);
110
122
  if (data.others) parts.push(`${data.others} other tool${plural(data.others)}`);
111
- if (data.commands) parts.push(`ran ${data.commands} command${plural(data.commands)}`);
112
123
  if (data.failed) parts.push(`${data.failed} failed`);
113
124
  return parts;
114
125
  }
115
126
 
116
- /** 纯文本摘要行(旧 compact-style 格式):"Read 3 files, edited 2 files · 42s"。 */
127
+ /** 纯文本摘要行:句首大写 + 可选耗时。 */
117
128
  export function summaryLine(data: AgentSummaryData): string {
118
129
  const parts = summaryParts(data);
119
130
  if (parts.length === 0) return "";
@@ -125,13 +136,8 @@ export function summaryLine(data: AgentSummaryData): string {
125
136
 
126
137
  /**
127
138
  * Markdown 摘要行。
128
- * `box` 为 true:markdown 引用块 `> *斜体内容*`(渲染为引用,主题 mdQuote=muted 即灰色,
129
- * 内容斜体)。entry renderer 场景直接用。
130
- * `box` 为 false:整体加粗单行。
131
- * `colors`:成功/失败计数的 ANSI 前缀,取自主题(`theme.getFgAnsi("success")` /
132
- * `theme.getFgAnsi("error")`),缺省不染色。仅数字染色:成功计数的数字染
133
- * success 色、failed 计数的数字染 error 色,文本与时长不染色。颜色 span 以
134
- * `\x1b[0m` 复位,引用块渲染器会在复位后重贴引用样式,后续文本不受影响。
139
+ * `box` 为 true:引用块 `> *斜体*`;false:整体加粗。
140
+ * `colors`:仅数字染色(success / failed)。
135
141
  */
136
142
  export function summaryMarkdown(
137
143
  data: AgentSummaryData,
@@ -140,12 +146,10 @@ export function summaryMarkdown(
140
146
  ): string {
141
147
  const parts = summaryParts(data);
142
148
  if (parts.length === 0) return "";
143
- // 仅首段动词大写(与纯文本版“句首大写”一致)
144
149
  const capitalizeFirst = (part: string, first: boolean) => {
145
150
  const verb = part.match(/^[a-z]+/)?.[0] ?? "";
146
151
  return first && verb ? verb[0].toUpperCase() + verb.slice(1) + part.slice(verb.length) : part;
147
152
  };
148
- // 仅染数字:`Read 2 files` → `Read <色>2</色> files`
149
153
  const paintNumber = (code: string, part: string) =>
150
154
  code ? part.replace(/(\d+)/, `${code}$1\x1b[0m`) : part;
151
155
  const text = parts
@@ -159,11 +163,9 @@ export function summaryMarkdown(
159
163
 
160
164
  /**
161
165
  * 绑定 pi 事件到摘要统计:
162
- * - agent_start 重置统计
163
- * - tool_execution_start / tool_execution_end 累计
164
- * - agent_end 时回调快照(工具数 < minToolCount 不回调:单工具行本身已是摘要)
165
- *
166
- * 返回取消函数:清除当前统计引用(pi.on 不支持解绑,取消后不再产生回调)。
166
+ * - agent_start 重置
167
+ * - tool_execution_start / end 累计
168
+ * - agent_end 回调(toolCount < minToolCount 跳过)
167
169
  */
168
170
  export function bindAgentSummary(
169
171
  pi: ExtensionAPI,
@@ -2,7 +2,7 @@
2
2
  * Agent 回合摘要展示:agent_end 时把本回合工具统计写入会话条目,
3
3
  * 由 entry renderer 渲染为 markdown 引用块 `> [!TIP] *斜体内容*`。
4
4
  *
5
- * 统计复用 utils/agent-summary.ts(口径同旧 compact-style,ea64df0 删除)。
5
+ * 统计复用 ./core.ts(bash/read/edit/write/other)。
6
6
  * appendEntry 不进 LLM 上下文,只显示在聊天区。
7
7
  * 引用块文字色取主题 mdQuote(cc 主题下为 muted 灰),内容用 *斜体* 语法。
8
8
  */
@@ -10,11 +10,7 @@
10
10
  import { Markdown } from "@earendil-works/pi-tui";
11
11
  import { getMarkdownTheme } from "@earendil-works/pi-coding-agent";
12
12
  import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
13
- import {
14
- bindAgentSummary,
15
- summaryMarkdown,
16
- type AgentSummaryData,
17
- } from "../utils/agent-summary.ts";
13
+ import { bindAgentSummary, summaryMarkdown, type AgentSummaryData } from "./core.ts";
18
14
 
19
15
  export const AGENT_SUMMARY_ENTRY_TYPE = "agent-summary";
20
16
 
@@ -20,7 +20,7 @@ import {
20
20
  sessionTitle,
21
21
  type ReferenceSessionInfo,
22
22
  type ReferenceSource,
23
- } from "./session-reference-core.ts";
23
+ } from "./session.ts";
24
24
 
25
25
  const MAX_SESSION_SUGGESTIONS = 3;
26
26
  const MAX_FILE_SUGGESTIONS = 7;
@@ -1,7 +1,7 @@
1
1
  import { VERSION, type AppKeybinding } from "@earendil-works/pi-coding-agent";
2
2
  import { getKeybindings } from "@earendil-works/pi-tui";
3
3
  import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
4
- import { config } from "../config/config.ts";
4
+ import { config } from "../../config/config.ts";
5
5
 
6
6
  type Rgb = [number, number, number];
7
7
  type StyledPart = {
@@ -1,43 +1,32 @@
1
1
  import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
2
- import agentAutocomplete from "./feature/agent-autocomplete.ts";
3
- import agentSummary from "./feature/agent-summary.ts";
4
- import claudeCodeStyle, { getCompactThinkingConfig } from "./renderer/index.ts";
5
- import {
6
- installCompactThinking,
7
- type CompactThinkingController,
8
- } from "./feature/compact-thinking.ts";
2
+
3
+ // shell
4
+ import piAliases from "./feature/shell/aliases.ts";
5
+ import piStartupHeader from "./feature/shell/startup-header.ts";
6
+ import workingMessage from "./feature/shell/working-message.ts";
7
+
8
+ // feature
9
+ import agentAutocomplete from "./feature/reference/subagent.ts";
10
+ import agentSummary from "./feature/agent-summary/index.ts";
9
11
  import context from "./feature/context.ts";
10
- import markdownEnhance from "./feature/markdown-enhance.ts";
11
- import piAliases from "./feature/pi-aliases.ts";
12
- import piStartupHeader from "./feature/pi-startup-header.ts";
13
- import sessionReference from "./feature/session-reference.ts";
14
- import workingMessage from "./feature/working-message.ts";
12
+ import sessionReference from "./feature/reference/index.ts";
13
+ import { installCompactThinking } from "./feature/compact-thinking.ts";
14
+
15
+ // renderer
16
+ import claudeCodeStyle, { getCompactThinkingConfig } from "./renderer/index.ts";
17
+ import markdownEnhance from "./renderer/markdown-enhance.ts";
15
18
 
16
19
  export default function (pi: ExtensionAPI): void {
20
+ // shell chrome
17
21
  piAliases(pi);
18
22
  piStartupHeader(pi);
19
- markdownEnhance(pi);
20
- let compactThinking: CompactThinkingController | undefined;
21
- const compactThinkingBridge: CompactThinkingController = {
22
- updateConfig(next) {
23
- compactThinking?.updateConfig(next);
24
- },
25
- getMessageThinkingDurationMs(messageTimestamp) {
26
- return compactThinking?.getMessageThinkingDurationMs?.(messageTimestamp);
27
- },
28
- isMessageThinkingActive(messageTimestamp) {
29
- return compactThinking?.isMessageThinkingActive?.(messageTimestamp) ?? false;
30
- },
31
- getThinkingAnimationFrame() {
32
- return compactThinking?.getThinkingAnimationFrame?.() ?? 0;
33
- },
34
- setCompactSummaryActive(active) {
35
- compactThinking?.setCompactSummaryActive?.(active);
36
- },
37
- };
38
- claudeCodeStyle(pi, undefined, compactThinkingBridge);
39
- compactThinking = installCompactThinking(pi, getCompactThinkingConfig());
40
23
  workingMessage(pi);
24
+
25
+ // render stack:thinking controller 直接交给 style 作 query
26
+ markdownEnhance(pi);
27
+ claudeCodeStyle(pi, undefined, installCompactThinking(pi, getCompactThinkingConfig()));
28
+
29
+ // features
41
30
  context(pi);
42
31
  sessionReference(pi);
43
32
  agentAutocomplete(pi);