@herbertgao/pi-extensions 2026.9.19 → 2026.9.20

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 (186) hide show
  1. package/README.md +1 -8
  2. package/node_modules/@herbertgao/pi-cc-extensions/README.en.md +76 -59
  3. package/node_modules/@herbertgao/pi-cc-extensions/README.md +76 -59
  4. package/node_modules/@herbertgao/pi-cc-extensions/assets/readme/preview.webp +0 -0
  5. package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/config.ts +93 -34
  6. package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/panel.ts +346 -117
  7. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/agent-summary/core.ts +6 -36
  8. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/agent-summary/index.ts +2 -2
  9. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/compact-thinking.ts +24 -29
  10. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/context.ts +330 -360
  11. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/reference/index.ts +56 -108
  12. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/reference/session.ts +97 -15
  13. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/reference/subagent.ts +80 -45
  14. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/shell/flush-docked-bash.ts +36 -0
  15. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/shell/footer-layout.ts +229 -0
  16. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/shell/footer.ts +479 -0
  17. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/shell/startup-header.ts +92 -61
  18. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/shell/working-message.ts +58 -38
  19. package/node_modules/@herbertgao/pi-cc-extensions/extensions/index.ts +19 -3
  20. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/compact-mode.ts +1080 -229
  21. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/default-mode.ts +232 -259
  22. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/index.ts +38 -48
  23. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/markdown-enhance.ts +8 -2
  24. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/hover.ts +2 -7
  25. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/interaction.ts +277 -113
  26. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/layout.ts +15 -6
  27. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/packets.ts +18 -72
  28. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/scroll.ts +61 -26
  29. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/ansi-utils.ts +25 -57
  30. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-component.ts +125 -0
  31. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-edit-render.ts +227 -0
  32. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-header.ts +136 -0
  33. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-highlight.ts +115 -0
  34. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-inline.ts +324 -0
  35. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-layout.ts +762 -0
  36. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-limits.ts +152 -0
  37. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-palette.ts +410 -0
  38. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-parse.ts +535 -0
  39. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-presentation.ts +2 -2
  40. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-renderer.ts +21 -3219
  41. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-text.ts +44 -0
  42. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-write-render.ts +568 -0
  43. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/index.ts +19 -18
  44. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/line-width-safety.ts +2 -2
  45. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/write-execution.ts +1 -0
  46. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/grouping.ts +142 -192
  47. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/mcp-title.ts +39 -0
  48. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/{message-display.ts → tool/message-display.ts} +24 -90
  49. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/names.ts +426 -0
  50. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/result.ts +90 -132
  51. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/{show-more-hint.ts → tool/show-more-hint.ts} +10 -0
  52. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/transcript-refresh.ts +8 -26
  53. package/node_modules/@herbertgao/pi-cc-extensions/extensions/utils/ansi-color.ts +44 -0
  54. package/node_modules/@herbertgao/pi-cc-extensions/extensions/utils/ansi-text.ts +76 -0
  55. package/node_modules/@herbertgao/pi-cc-extensions/extensions/utils/component-tree.ts +34 -0
  56. package/node_modules/@herbertgao/pi-cc-extensions/extensions/utils/format.ts +28 -0
  57. package/node_modules/@herbertgao/pi-cc-extensions/extensions/utils/fullscreen-detect.ts +51 -0
  58. package/node_modules/@herbertgao/pi-cc-extensions/extensions/utils/patch-keys.ts +124 -0
  59. package/node_modules/@herbertgao/pi-cc-extensions/extensions/utils/sgr-mouse.ts +70 -0
  60. package/node_modules/@herbertgao/pi-cc-extensions/package.json +7 -7
  61. package/package.json +3 -7
  62. package/node_modules/@herbertgao/pi-cc-extensions/assets/readme/hero.en.svg +0 -101
  63. package/node_modules/@herbertgao/pi-cc-extensions/assets/readme/hero.svg +0 -101
  64. package/node_modules/@herbertgao/pi-cc-extensions/assets/readme/welcome.webp +0 -0
  65. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/render-utils.ts +0 -5
  66. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/types.ts +0 -30
  67. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/write-display-utils.ts +0 -12
  68. package/node_modules/pi-footer/CHANGELOG.md +0 -145
  69. package/node_modules/pi-footer/LICENSE +0 -21
  70. package/node_modules/pi-footer/README.md +0 -354
  71. package/node_modules/pi-footer/package.json +0 -68
  72. package/node_modules/pi-footer/src/cache.ts +0 -106
  73. package/node_modules/pi-footer/src/colors.ts +0 -237
  74. package/node_modules/pi-footer/src/config.ts +0 -202
  75. package/node_modules/pi-footer/src/event-widgets.ts +0 -41
  76. package/node_modules/pi-footer/src/extension-statuses.ts +0 -102
  77. package/node_modules/pi-footer/src/git.ts +0 -135
  78. package/node_modules/pi-footer/src/index.ts +0 -268
  79. package/node_modules/pi-footer/src/metrics.ts +0 -141
  80. package/node_modules/pi-footer/src/presets.ts +0 -383
  81. package/node_modules/pi-footer/src/render.ts +0 -114
  82. package/node_modules/pi-footer/src/separators.ts +0 -52
  83. package/node_modules/pi-footer/src/types.ts +0 -122
  84. package/node_modules/pi-footer/src/ui/color-level-confirm.ts +0 -22
  85. package/node_modules/pi-footer/src/ui/color-options.ts +0 -195
  86. package/node_modules/pi-footer/src/ui/config-lifecycle.ts +0 -61
  87. package/node_modules/pi-footer/src/ui/edit-colors.ts +0 -13
  88. package/node_modules/pi-footer/src/ui/events.ts +0 -35
  89. package/node_modules/pi-footer/src/ui/extension-status-picker.ts +0 -60
  90. package/node_modules/pi-footer/src/ui/extension-statuses.ts +0 -73
  91. package/node_modules/pi-footer/src/ui/fields.ts +0 -252
  92. package/node_modules/pi-footer/src/ui/global-menu.ts +0 -126
  93. package/node_modules/pi-footer/src/ui/helpers.ts +0 -44
  94. package/node_modules/pi-footer/src/ui/layout.ts +0 -17
  95. package/node_modules/pi-footer/src/ui/line-list.ts +0 -19
  96. package/node_modules/pi-footer/src/ui/model.ts +0 -64
  97. package/node_modules/pi-footer/src/ui/navigation.ts +0 -29
  98. package/node_modules/pi-footer/src/ui/option-edit.ts +0 -93
  99. package/node_modules/pi-footer/src/ui/overlay-render.ts +0 -103
  100. package/node_modules/pi-footer/src/ui/screen-context.ts +0 -18
  101. package/node_modules/pi-footer/src/ui/screen-controller.ts +0 -27
  102. package/node_modules/pi-footer/src/ui/screen-render.ts +0 -32
  103. package/node_modules/pi-footer/src/ui/screen-state.ts +0 -20
  104. package/node_modules/pi-footer/src/ui/screen.ts +0 -243
  105. package/node_modules/pi-footer/src/ui/screens/add-widget.ts +0 -92
  106. package/node_modules/pi-footer/src/ui/screens/confirm-exit.ts +0 -52
  107. package/node_modules/pi-footer/src/ui/screens/controller.ts +0 -12
  108. package/node_modules/pi-footer/src/ui/screens/edit-colors.ts +0 -68
  109. package/node_modules/pi-footer/src/ui/screens/edit-widget.ts +0 -115
  110. package/node_modules/pi-footer/src/ui/screens/extension-status-row.ts +0 -61
  111. package/node_modules/pi-footer/src/ui/screens/global.ts +0 -75
  112. package/node_modules/pi-footer/src/ui/screens/line-list.ts +0 -108
  113. package/node_modules/pi-footer/src/ui/screens/main.ts +0 -99
  114. package/node_modules/pi-footer/src/ui/screens/terminal.ts +0 -121
  115. package/node_modules/pi-footer/src/ui/screens/widget-list.ts +0 -154
  116. package/node_modules/pi-footer/src/ui/terminal-menu.ts +0 -32
  117. package/node_modules/pi-footer/src/ui/theme.ts +0 -48
  118. package/node_modules/pi-footer/src/ui/title-bar.ts +0 -100
  119. package/node_modules/pi-footer/src/ui/widget-actions.ts +0 -76
  120. package/node_modules/pi-footer/src/ui.ts +0 -66
  121. package/node_modules/pi-footer/src/widgets/context.ts +0 -28
  122. package/node_modules/pi-footer/src/widgets/core/active-tools.ts +0 -17
  123. package/node_modules/pi-footer/src/widgets/core/context-window.ts +0 -24
  124. package/node_modules/pi-footer/src/widgets/core/cwd-basename.ts +0 -19
  125. package/node_modules/pi-footer/src/widgets/core/cwd.ts +0 -108
  126. package/node_modules/pi-footer/src/widgets/core/event.ts +0 -34
  127. package/node_modules/pi-footer/src/widgets/core/external-status.ts +0 -102
  128. package/node_modules/pi-footer/src/widgets/core/model-provider.ts +0 -20
  129. package/node_modules/pi-footer/src/widgets/core/model.ts +0 -35
  130. package/node_modules/pi-footer/src/widgets/core/provider.ts +0 -17
  131. package/node_modules/pi-footer/src/widgets/core/session-name.ts +0 -17
  132. package/node_modules/pi-footer/src/widgets/core/text-verbosity.ts +0 -17
  133. package/node_modules/pi-footer/src/widgets/core/thinking-level.ts +0 -17
  134. package/node_modules/pi-footer/src/widgets/git/ahead-behind.ts +0 -17
  135. package/node_modules/pi-footer/src/widgets/git/branch.ts +0 -81
  136. package/node_modules/pi-footer/src/widgets/git/clean.ts +0 -19
  137. package/node_modules/pi-footer/src/widgets/git/deletions.ts +0 -17
  138. package/node_modules/pi-footer/src/widgets/git/diff.ts +0 -38
  139. package/node_modules/pi-footer/src/widgets/git/insertions.ts +0 -17
  140. package/node_modules/pi-footer/src/widgets/git/remote.ts +0 -17
  141. package/node_modules/pi-footer/src/widgets/git/root.ts +0 -17
  142. package/node_modules/pi-footer/src/widgets/git/sha.ts +0 -17
  143. package/node_modules/pi-footer/src/widgets/git/staged.ts +0 -17
  144. package/node_modules/pi-footer/src/widgets/git/status.ts +0 -19
  145. package/node_modules/pi-footer/src/widgets/git/unstaged.ts +0 -17
  146. package/node_modules/pi-footer/src/widgets/git/untracked.ts +0 -17
  147. package/node_modules/pi-footer/src/widgets/instance.ts +0 -118
  148. package/node_modules/pi-footer/src/widgets/layout/custom-text.ts +0 -18
  149. package/node_modules/pi-footer/src/widgets/layout/flex-separator.ts +0 -32
  150. package/node_modules/pi-footer/src/widgets/layout/separator.ts +0 -57
  151. package/node_modules/pi-footer/src/widgets/layout/spacer.ts +0 -31
  152. package/node_modules/pi-footer/src/widgets/options.ts +0 -122
  153. package/node_modules/pi-footer/src/widgets/project/runtime.ts +0 -361
  154. package/node_modules/pi-footer/src/widgets/registry.ts +0 -223
  155. package/node_modules/pi-footer/src/widgets/session/assistant-messages.ts +0 -17
  156. package/node_modules/pi-footer/src/widgets/session/compactions.ts +0 -17
  157. package/node_modules/pi-footer/src/widgets/session/elapsed.ts +0 -18
  158. package/node_modules/pi-footer/src/widgets/session/last-activity.ts +0 -18
  159. package/node_modules/pi-footer/src/widgets/session/messages.ts +0 -19
  160. package/node_modules/pi-footer/src/widgets/session/session-id.ts +0 -17
  161. package/node_modules/pi-footer/src/widgets/session/session-start.ts +0 -18
  162. package/node_modules/pi-footer/src/widgets/session/tool-results.ts +0 -17
  163. package/node_modules/pi-footer/src/widgets/session/total-messages.ts +0 -19
  164. package/node_modules/pi-footer/src/widgets/session/total-time.ts +0 -18
  165. package/node_modules/pi-footer/src/widgets/session/user-messages.ts +0 -17
  166. package/node_modules/pi-footer/src/widgets/store.ts +0 -26
  167. package/node_modules/pi-footer/src/widgets/tokens/cache-hit-rate.ts +0 -55
  168. package/node_modules/pi-footer/src/widgets/tokens/cache-read.ts +0 -18
  169. package/node_modules/pi-footer/src/widgets/tokens/cache-write.ts +0 -18
  170. package/node_modules/pi-footer/src/widgets/tokens/context-bar.ts +0 -108
  171. package/node_modules/pi-footer/src/widgets/tokens/context-length.ts +0 -26
  172. package/node_modules/pi-footer/src/widgets/tokens/context-remaining.ts +0 -29
  173. package/node_modules/pi-footer/src/widgets/tokens/context.ts +0 -29
  174. package/node_modules/pi-footer/src/widgets/tokens/cost.ts +0 -51
  175. package/node_modules/pi-footer/src/widgets/tokens/input-speed.ts +0 -25
  176. package/node_modules/pi-footer/src/widgets/tokens/input-tokens.ts +0 -18
  177. package/node_modules/pi-footer/src/widgets/tokens/output-speed.ts +0 -25
  178. package/node_modules/pi-footer/src/widgets/tokens/output-tokens.ts +0 -18
  179. package/node_modules/pi-footer/src/widgets/tokens/tokens.ts +0 -20
  180. package/node_modules/pi-footer/src/widgets/tokens/total-speed.ts +0 -25
  181. package/node_modules/pi-footer/src/widgets/tokens/total-tokens.ts +0 -18
  182. package/node_modules/pi-footer/src/widgets/types.ts +0 -181
  183. package/node_modules/pi-footer/src/widgets/utils/colors.ts +0 -11
  184. package/node_modules/pi-footer/src/widgets/utils/context.ts +0 -112
  185. package/node_modules/pi-footer/src/widgets/utils/session.ts +0 -19
  186. package/node_modules/pi-footer/src/widgets/utils/token-format.ts +0 -78
@@ -1,4 +1,4 @@
1
- import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
1
+ import { ToolExecutionComponent, type ExtensionAPI } from "@earendil-works/pi-coding-agent";
2
2
  import type { CompactThinkingController } from "../feature/compact-thinking.ts";
3
3
  import { installToolGrouping, type ToolGroupingHooks } from "./tool/grouping.ts";
4
4
  import {
@@ -12,14 +12,14 @@ import {
12
12
  installToolExpandedBackground,
13
13
  type DefaultModeHooks,
14
14
  } from "./default-mode.ts";
15
- import { isLazyProxyTui } from "../utils/fullscreen-detect.ts";
15
+ import { installMainScreenDoRenderPatch, isLazyProxyTui } from "../utils/fullscreen-detect.ts";
16
16
  import { showCcstylePanel } from "../config/panel.ts";
17
17
  import {
18
18
  config,
19
19
  formatConfigStatus,
20
20
  normalizeConfig,
21
- saveConfig,
22
21
  setConfig,
22
+ updateConfig,
23
23
  type CompactStyleMode,
24
24
  type Config,
25
25
  } from "../config/config.ts";
@@ -27,19 +27,19 @@ import {
27
27
  installToolMouseInteraction,
28
28
  resetToolHoverState,
29
29
  scheduleSessionRender,
30
- setHoveredToolGroup,
31
- setHoveredToolIo,
32
30
  teardownToolMouseInteraction,
33
31
  TOOL_MOUSE_DISABLE,
34
32
  } from "./mouse/interaction.ts";
35
- import { getToolMouseTui } from "./mouse/scroll.ts";
33
+ import { getToolMouseTui, noteNewTranscriptItem } from "./mouse/scroll.ts";
34
+ import { setHoveredToolGroup, setHoveredToolIo } from "./mouse/hover.ts";
36
35
  import { clearAllAnimations } from "./tool/result.ts";
37
36
  import { installWriteOverride, WriteExecutionMetadataStore } from "./tool/diff/index.ts";
38
37
  import {
39
38
  installMessageDisplayRendering,
40
39
  refreshMessageDisplays,
41
40
  setMessageDisplayTheme,
42
- } from "./message-display.ts";
41
+ } from "./tool/message-display.ts";
42
+ import { GLOBAL_TOOL_RENDER_PATCH, patchRegistry } from "../utils/patch-keys.ts";
43
43
 
44
44
  /**
45
45
  * Claude Code Style for pi — 装配入口。
@@ -49,8 +49,6 @@ import {
49
49
  * 共用 → tool-grouping / message-display / mouse / write override
50
50
  */
51
51
 
52
- const GLOBAL_COMPACTION_RENDER_PATCH = Symbol.for("pi.ccstyle.compaction-render-patch");
53
-
54
52
  let compactModeHooks: CompactModeHooks | undefined;
55
53
 
56
54
  function refreshCurrentTranscript(ctx?: any, toolGrouping?: ToolGroupingHooks): void {
@@ -69,8 +67,7 @@ function syncCompactMode(ctx: any): void {
69
67
  }
70
68
 
71
69
  function applyStyleMode(mode: CompactStyleMode, ctx: any, toolGrouping?: ToolGroupingHooks): void {
72
- config.mode = mode;
73
- saveConfig();
70
+ updateConfig({ mode });
74
71
  if (mode === "off") {
75
72
  // Native rendering:清 hover/click,关闭鼠标上报以恢复终端默认滚轮。
76
73
  resetToolHoverState();
@@ -96,18 +93,6 @@ function applyStyleMode(mode: CompactStyleMode, ctx: any, toolGrouping?: ToolGro
96
93
  ctx.ui.notify(`Claude Code style: ${mode}`, "info");
97
94
  }
98
95
 
99
- type LegacyCompactionRenderPatch = {
100
- enabled?: () => boolean;
101
- };
102
-
103
- /** Disable the pre-native compaction monkey patch left alive by /reload. */
104
- function deactivateLegacyCompactionRendering() {
105
- const patch = (globalThis as any)[GLOBAL_COMPACTION_RENDER_PATCH] as
106
- | LegacyCompactionRenderPatch
107
- | undefined;
108
- if (patch) patch.enabled = () => false;
109
- }
110
-
111
96
  export default function (
112
97
  pi: ExtensionAPI,
113
98
  configOverride?: Partial<Config>,
@@ -132,6 +117,12 @@ export default function (
132
117
  // 渲染层(工具样式/分组)是原型与组件级 patch,fullscreen 官方布局
133
118
  // 同样渲染这些组件,因此两种模式都安装。
134
119
  if (installation) return installation;
120
+ // reload 接管:上一代 global tool patch 断开后,其 mode() 闭包仍读旧模块
121
+ // config(应为 off);先固定为 off,避免陈旧回调继续参与渲染决策。
122
+ const staleGlobalPatch = patchRegistry.get<{ mode: () => string }>(GLOBAL_TOOL_RENDER_PATCH);
123
+ if (staleGlobalPatch) staleGlobalPatch.mode = () => "off";
124
+ // regular 主屏的差分渲染补丁:视口上方变化不再触发清回滚的 fullRender。
125
+ installMainScreenDoRenderPatch();
135
126
  const defaultMode = installDefaultMode(writeExecutionMetadata);
136
127
  const toolGrouping = installToolGrouping(() => config.mode === "on");
137
128
  const compactMode = installCompactMode({
@@ -142,7 +133,6 @@ export default function (
142
133
  const disposeMessageDisplay = installMessageDisplayRendering();
143
134
  // 展开背景必须在 compact-mode 之后装,shutdown 时先于 compact 释放。
144
135
  const disposeToolExpandedBackground = installToolExpandedBackground();
145
- deactivateLegacyCompactionRendering();
146
136
  installation = {
147
137
  defaultMode,
148
138
  toolGrouping,
@@ -206,6 +196,13 @@ export default function (
206
196
  }
207
197
  });
208
198
 
199
+ // 回到底部按钮的累计计数:离开底部期间每落一块内容 +1。
200
+ pi.on("message_start", async (event) => {
201
+ const role = event.message?.role;
202
+ // toolResult 不单独成块(渲染在工具卡内),跳过以免与工具卡重复计数。
203
+ if (role === "user" || role === "assistant" || role === "custom") noteNewTranscriptItem();
204
+ });
205
+
209
206
  pi.on("tool_execution_end", async (event) => {
210
207
  if (config.mode !== "compact") return;
211
208
  // Agent 等工具收尾后延迟刷新,让 compact-thinking 先落最终态。
@@ -215,20 +212,17 @@ export default function (
215
212
  }, 0);
216
213
  });
217
214
 
218
- pi.on("session_start", async (_event, ctx) => {
219
- // Confirm write ownership one tick after every extension's session_start has run:
220
- // others register tools in their own session_start, and registering first would
221
- // silently drop their write (first registration wins).
215
+ pi.on("session_start", async (event, ctx) => {
216
+ // 延后一拍再确认 write 归属:其他扩展同样在各自的 session_start 里注册工具,
217
+ // 本 handler 执行时可能还看不到对方,此时注册会与对方撞名(注册表先到先得),
218
+ // 对方的 write 会被静默丢弃。等所有 session_start 跑完,检测结果才是权威的。
222
219
  setTimeout(() => {
223
220
  installWriteOverride(pi, writeExecutionMetadata, (owner) => {
224
- try {
225
- ctx.ui?.notify?.(
226
- `ccstyle: write is owned by ${owner.path || owner.source}; rich diff yields`,
227
- "warning",
228
- );
229
- } catch {
230
- // ctx may be stale by the next tick; the notice is decorative.
231
- }
221
+ // 冲突可见:对方接管 write 后本插件不再提供富 diff。
222
+ ctx.ui?.notify?.(
223
+ `ccstyle: write 工具已被 ${owner.path || owner.source} 占用,富 diff 已让位`,
224
+ "warning",
225
+ );
232
226
  });
233
227
  }, 0);
234
228
  const hooks = ensureTuiInstallation(ctx);
@@ -247,7 +241,7 @@ export default function (
247
241
  scheduleSessionRender(() => hooks.toolGrouping.refresh(getToolMouseTui()));
248
242
  });
249
243
 
250
- pi.on("session_compact", async (_event, ctx) => {
244
+ pi.on("session_compact", async (event, ctx) => {
251
245
  const hooks = ensureTuiInstallation(ctx);
252
246
  // Compaction rebuilds the transcript without session_start. Rebind after
253
247
  // other TUI extensions may have replaced the root input dispatcher.
@@ -262,7 +256,7 @@ export default function (
262
256
  });
263
257
  });
264
258
 
265
- pi.on("session_tree", async (_event, ctx) => {
259
+ pi.on("session_tree", async (event, ctx) => {
266
260
  // 会话树重建后在当前帧和下一帧各同步一次,替换旧组件引用。
267
261
  if (ctx?.mode !== "tui" || !ctx?.hasUI) return;
268
262
  syncCompactMode(ctx);
@@ -271,6 +265,7 @@ export default function (
271
265
 
272
266
  pi.on("tool_execution_start", async (_event, ctx) => {
273
267
  installation?.toolGrouping.setTheme(ctx.ui.theme);
268
+ noteNewTranscriptItem();
274
269
  });
275
270
 
276
271
  pi.on("session_shutdown", async () => {
@@ -279,20 +274,13 @@ export default function (
279
274
  // 但 onTerminalInput 监听与 handleViewportInput 包装仍需释放。
280
275
  teardownToolMouseInteraction(mouseOwner);
281
276
  const current = installation;
282
- if (!current) return;
283
- if (!current.defaultMode.isOwner()) {
284
- // Replacement installers already disposed these owner-aware patches.
285
- // Drop only this stale runtime's closure; global teardown belongs to the owner.
286
- installation = undefined;
287
- return;
288
- }
277
+ if (!current || !current.defaultMode.isOwner()) return;
289
278
  current.defaultMode.shutdown();
290
279
  current.toolGrouping.shutdown();
291
280
  current.disposeToolExpandedBackground();
292
281
  current.compactMode.shutdown();
293
282
  compactModeHooks = undefined;
294
283
  current.disposeMessageDisplay();
295
- deactivateLegacyCompactionRendering();
296
284
  clearAllAnimations();
297
285
  installation = undefined;
298
286
  });
@@ -301,11 +289,13 @@ export default function (
301
289
  // ---- 对外导出:入口/测试实际消费的符号 ----
302
290
  export { getCompactThinkingConfig } from "../config/config.ts";
303
291
  export {
304
- humanizeMcpToolName,
305
- isMcpToolDefinition,
306
292
  preservesOriginalRenderer,
307
293
  shouldRenderRichDiff,
308
294
  } from "./default-mode.ts";
295
+ export {
296
+ isMcpToolDefinition,
297
+ mcpToolTitle,
298
+ } from "./tool/mcp-title.ts";
309
299
  export {
310
300
  ExpandedToolIoView,
311
301
  ExpandedToolResultText,
@@ -69,7 +69,9 @@ function renderAdmonition(lines: string[], i: number): { output: string[]; next:
69
69
  j++;
70
70
  }
71
71
  while (body.length > 0 && body[body.length - 1].trim() === "") body.pop();
72
+ // 内容合并为一行,作为引用块正文
72
73
  const content = body.join(" ").trim();
74
+ // 保留引用块形态(pi 渲染为左侧竖线),标签加粗
73
75
  return {
74
76
  output: [`> **${style.icon} ${style.label}**${content ? ` ${content}` : ""}`, ""],
75
77
  next: j,
@@ -83,10 +85,13 @@ function renderAdmonition(lines: string[], i: number): { output: string[]; next:
83
85
  const URL_RE = /(?<!<)(?<!\]\()https?:\/\/[^\s<>'"|,。;:!?、」』】()【】《》『』「」]+/g;
84
86
  const TRIM_URL_RE = /[.,;:!?】」』"'》)}]+$/;
85
87
 
86
- /** 去掉 URL 尾部标点;括号按平衡保留(如 Wikipedia 链接含括号)。 */
88
+ /**
89
+ * 去掉 URL 尾部标点;括号按平衡保留(如 Wikipedia 链接含括号、
90
+ * IPv6 地址含 [::1]),尾部不成对的 ] 与 ) 会截掉。
91
+ */
87
92
  function trimUrl(url: string): string {
88
93
  let t = url.replace(TRIM_URL_RE, "");
89
- while (true) {
94
+ for (;;) {
90
95
  if (t.endsWith(")") && (t.match(/\(/g)?.length ?? 0) < (t.match(/\)/g)?.length ?? 0)) {
91
96
  t = t.slice(0, -1);
92
97
  } else if (t.endsWith("]") && (t.match(/\[/g)?.length ?? 0) < (t.match(/\]/g)?.length ?? 0)) {
@@ -296,6 +301,7 @@ export default function (pi: ExtensionAPI): void {
296
301
  // 所以三个转换合并为一次注册,内部按序链式执行。
297
302
  pi.registerMarkdownTransformer((markdown, context) => {
298
303
  const { messageType, isStreaming = false } = context ?? {};
304
+ // thinking 保持原文;普通回复即使流式中也先关闭跨行链接的空白点击区。
299
305
  if (messageType === "assistant-thinking") return markdown;
300
306
  markdown = normalizeMultilineLinks(markdown);
301
307
  if (isStreaming) return markdown;
@@ -1,5 +1,6 @@
1
1
  import { ThinkingPreviewBlock } from "../../feature/compact-thinking.ts";
2
2
  import { setHoveredCompactAssistant } from "../compact-mode.ts";
3
+ import { patchRegistry, TOOL_HOVER_STATE_KEY } from "../../utils/patch-keys.ts";
3
4
  import {
4
5
  isExpandedToolIoView,
5
6
  invalidateIoView,
@@ -10,8 +11,6 @@ import type { ToolGroupComponent } from "../tool/grouping.ts";
10
11
  import { componentAtLocalRow, type ComponentRowHit } from "./layout.ts";
11
12
  import { setScrollButtonHovered } from "./scroll.ts";
12
13
 
13
- const TOOL_HOVER_STATE_KEY = Symbol.for("pi.ccstyle.tool-hover-state");
14
-
15
14
  type SharedToolHoverState = { toolCallId: string | null };
16
15
 
17
16
  /**
@@ -19,14 +18,10 @@ type SharedToolHoverState = { toolCallId: string | null };
19
18
  * 测试依赖该跨实例语义。
20
19
  */
21
20
  export function sharedToolHoverState(): SharedToolHoverState {
22
- const host = globalThis as any;
23
- return (host[TOOL_HOVER_STATE_KEY] ??= { toolCallId: null });
21
+ return patchRegistry.ensure(TOOL_HOVER_STATE_KEY, () => ({ toolCallId: null }));
24
22
  }
25
23
 
26
- export let hoveredToolCallId: string | null = sharedToolHoverState().toolCallId;
27
-
28
24
  export function setHoveredToolCallId(toolCallId: string | null): void {
29
- hoveredToolCallId = toolCallId;
30
25
  sharedToolHoverState().toolCallId = toolCallId;
31
26
  }
32
27