@herbertgao/pi-extensions 2026.10.4 → 2026.10.6
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 +2 -2
- package/node_modules/@herbertgao/pi-cc-extensions/README.en.md +13 -9
- package/node_modules/@herbertgao/pi-cc-extensions/README.md +13 -9
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/config.ts +72 -16
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/panel.ts +262 -48
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/agent-summary/core.ts +2 -3
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/compact-thinking.ts +1 -1
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/context.ts +131 -28
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/reference/index.ts +2 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/reference/subagent.ts +3 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/shell/footer-currency.ts +29 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/shell/footer.ts +96 -59
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/shell/git-stats.ts +162 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/shell/token-rate.ts +204 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/shell/working-message.ts +51 -86
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/compact-mode.ts +212 -74
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/default-mode.ts +50 -362
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/index.ts +35 -3
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/markdown-enhance.ts +16 -83
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/hover.ts +1 -1
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/interaction.ts +28 -26
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/packets.ts +1 -1
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/sticky-prompt.ts +450 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/ask-user-question.ts +173 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/ccstyle-tool.ts +467 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/codemode.ts +5 -9
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/ansi-utils.ts +1 -24
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-edit-render.ts +64 -11
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-limits.ts +1 -1
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-presentation.ts +41 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-renderer.ts +5 -1
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-text.ts +2 -1
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-write-render.ts +36 -10
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/line-width-safety.ts +1 -1
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/grouping.ts +140 -51
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/message-display.ts +1 -1
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/names.ts +44 -4
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/result.ts +34 -803
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/tool-io.ts +735 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/tool-state.ts +138 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/utils/format.ts +9 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/utils/patch-keys.ts +5 -0
- package/node_modules/@herbertgao/pi-cc-extensions/package.json +5 -4
- package/node_modules/@herbertgao/pi-cc-extensions/themes/cc-dark.json +2 -2
- package/node_modules/@herbertgao/pi-cc-extensions/themes/cc-light.json +3 -3
- package/node_modules/@herbertgao/pi-subagents/package.json +2 -1
- package/node_modules/@herbertgao/sol-pi/README.md +3 -3
- package/node_modules/@herbertgao/sol-pi/THIRD_PARTY_NOTICES.md +4 -4
- package/node_modules/@herbertgao/sol-pi/agents-install.md +3 -3
- package/node_modules/@herbertgao/sol-pi/docs/compatibility.md +1 -1
- package/package.json +2 -2
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/show-more-hint.ts +0 -48
|
@@ -141,14 +141,14 @@ function linkifyUrls(markdown: string): string {
|
|
|
141
141
|
// Nerd Font 补丁字形(U+2460-U+2473)ink 超界,DirectWrite 下渲染会压住相邻字符;
|
|
142
142
|
// 转成 ASCII "(n)" 后任何字体下宽度一致。U+2460-U+2473 连续,差值即序号。
|
|
143
143
|
const CIRCLED_RE = /[①-⑳]/g;
|
|
144
|
+
|
|
144
145
|
const BLOCKQUOTE_PREFIX = /^ {0,3}>[ \t]?/;
|
|
145
146
|
const CODE_FENCE_OPEN = /^ {0,3}(`{3,}|~{3,})/;
|
|
146
147
|
const CODE_FENCE_CLOSE = /^ {0,3}(`+|~+)[ \t]*$/;
|
|
147
148
|
|
|
148
|
-
type FenceLine = { blockquoteDepth: number; content: string };
|
|
149
149
|
type MarkdownFence = { marker: string; blockquoteDepth: number };
|
|
150
150
|
|
|
151
|
-
function parseFenceLine(line: string):
|
|
151
|
+
function parseFenceLine(line: string): { blockquoteDepth: number; content: string } {
|
|
152
152
|
let content = line;
|
|
153
153
|
let blockquoteDepth = 0;
|
|
154
154
|
while (BLOCKQUOTE_PREFIX.test(content)) {
|
|
@@ -178,83 +178,17 @@ function scanMarkdownFence(
|
|
|
178
178
|
};
|
|
179
179
|
}
|
|
180
180
|
|
|
181
|
-
function replaceCircled(text: string): string {
|
|
182
|
-
return text.replace(CIRCLED_RE, (ch) => `(${ch.codePointAt(0)! - 0x2460 + 1})`);
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
function backtickRunAt(
|
|
186
|
-
text: string,
|
|
187
|
-
start: number,
|
|
188
|
-
skipEscaped: boolean,
|
|
189
|
-
): { start: number; end: number } | null {
|
|
190
|
-
let index = text.indexOf("`", start);
|
|
191
|
-
while (index >= 0) {
|
|
192
|
-
let backslashes = 0;
|
|
193
|
-
for (let cursor = index - 1; cursor >= 0 && text[cursor] === "\\"; cursor--) backslashes++;
|
|
194
|
-
if (!skipEscaped || backslashes % 2 === 0) {
|
|
195
|
-
let end = index + 1;
|
|
196
|
-
while (text[end] === "`") end++;
|
|
197
|
-
return { start: index, end };
|
|
198
|
-
}
|
|
199
|
-
index = text.indexOf("`", index + 1);
|
|
200
|
-
}
|
|
201
|
-
return null;
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
/** 转换连续 prose(可跨行),但保留有效 inline code spans。 */
|
|
205
|
-
function deCircledProse(prose: string): string {
|
|
206
|
-
let cursor = 0;
|
|
207
|
-
let transformed = "";
|
|
208
|
-
while (cursor < prose.length) {
|
|
209
|
-
const opening = backtickRunAt(prose, cursor, true);
|
|
210
|
-
if (!opening) {
|
|
211
|
-
transformed += replaceCircled(prose.slice(cursor));
|
|
212
|
-
break;
|
|
213
|
-
}
|
|
214
|
-
let closing = backtickRunAt(prose, opening.end, false);
|
|
215
|
-
while (closing && closing.end - closing.start !== opening.end - opening.start) {
|
|
216
|
-
closing = backtickRunAt(prose, closing.end, false);
|
|
217
|
-
}
|
|
218
|
-
if (!closing) {
|
|
219
|
-
transformed += replaceCircled(prose.slice(cursor, opening.end));
|
|
220
|
-
cursor = opening.end;
|
|
221
|
-
continue;
|
|
222
|
-
}
|
|
223
|
-
transformed += replaceCircled(prose.slice(cursor, opening.start));
|
|
224
|
-
transformed += prose.slice(opening.start, closing.end);
|
|
225
|
-
cursor = closing.end;
|
|
226
|
-
}
|
|
227
|
-
return transformed;
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
/** 转换普通 Markdown 文本,但保留匹配 container 的 fenced blocks 与 inline code spans。 */
|
|
231
181
|
function deCircled(markdown: string): string {
|
|
232
|
-
const output: string[] = [];
|
|
233
|
-
let prose: string[] = [];
|
|
234
182
|
let fence: MarkdownFence | undefined;
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
if (scanned.protected) {
|
|
245
|
-
flushProse();
|
|
246
|
-
output.push(line);
|
|
247
|
-
continue;
|
|
248
|
-
}
|
|
249
|
-
if (parseFenceLine(line).content.trim() === "") {
|
|
250
|
-
flushProse();
|
|
251
|
-
output.push(line);
|
|
252
|
-
continue;
|
|
253
|
-
}
|
|
254
|
-
prose.push(line);
|
|
255
|
-
}
|
|
256
|
-
flushProse();
|
|
257
|
-
return output.join("\n");
|
|
183
|
+
return markdown
|
|
184
|
+
.split("\n")
|
|
185
|
+
.map((line) => {
|
|
186
|
+
const scanned = scanMarkdownFence(line, fence);
|
|
187
|
+
fence = scanned.fence;
|
|
188
|
+
if (scanned.protected) return line;
|
|
189
|
+
return line.replace(CIRCLED_RE, (ch) => `(${ch.codePointAt(0)! - 0x2460 + 1})`);
|
|
190
|
+
})
|
|
191
|
+
.join("\n");
|
|
258
192
|
}
|
|
259
193
|
|
|
260
194
|
// ============================================================================
|
|
@@ -280,13 +214,12 @@ function normalizeMultilineLinks(markdown: string): string {
|
|
|
280
214
|
};
|
|
281
215
|
for (const line of markdown.split("\n")) {
|
|
282
216
|
const scanned = scanMarkdownFence(line, fence);
|
|
217
|
+
const opening = !fence && scanned.fence;
|
|
218
|
+
const closing = fence && !scanned.fence;
|
|
283
219
|
fence = scanned.fence;
|
|
284
|
-
if (
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
} else {
|
|
288
|
-
prose.push(line);
|
|
289
|
-
}
|
|
220
|
+
if (opening || closing) flush();
|
|
221
|
+
if (scanned.protected) out.push(line);
|
|
222
|
+
else prose.push(line);
|
|
290
223
|
}
|
|
291
224
|
flush();
|
|
292
225
|
return out.join("\n");
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
invalidateIoView,
|
|
7
7
|
type ExpandedToolIoView,
|
|
8
8
|
type ToolIoSection,
|
|
9
|
-
} from "../tool/
|
|
9
|
+
} from "../tool/tool-io.ts";
|
|
10
10
|
import type { ToolGroupComponent } from "../tool/grouping.ts";
|
|
11
11
|
import { componentAtLocalRow, type ComponentRowHit } from "./layout.ts";
|
|
12
12
|
import { setScrollButtonHovered } from "./scroll.ts";
|
|
@@ -13,9 +13,8 @@ import {
|
|
|
13
13
|
setHoveredCompactAssistant,
|
|
14
14
|
} from "../compact-mode.ts";
|
|
15
15
|
import { isMessageDisplayComponent } from "../tool/message-display.ts";
|
|
16
|
-
import { config } from "../../config/config.ts";
|
|
17
16
|
import { isLazyProxyTui } from "../../utils/fullscreen-detect.ts";
|
|
18
|
-
import { setToolTuiFullscreen, isCollapseHintLine } from "../tool/
|
|
17
|
+
import { setToolTuiFullscreen, isCollapseHintLine } from "../tool/names.ts";
|
|
19
18
|
import {
|
|
20
19
|
type ExpandedToolIoView,
|
|
21
20
|
getActiveIoViewFrame,
|
|
@@ -23,7 +22,7 @@ import {
|
|
|
23
22
|
type IoViewFrameState,
|
|
24
23
|
setActiveIoViewFrame,
|
|
25
24
|
type ToolIoSection,
|
|
26
|
-
} from "../tool/
|
|
25
|
+
} from "../tool/tool-io.ts";
|
|
27
26
|
import {
|
|
28
27
|
collectToolComponents,
|
|
29
28
|
extractToolFramePlacements,
|
|
@@ -76,6 +75,11 @@ import {
|
|
|
76
75
|
setHoveredToolIo,
|
|
77
76
|
type FullscreenHoverTarget,
|
|
78
77
|
} from "./hover.ts";
|
|
78
|
+
import {
|
|
79
|
+
handleStickyPromptClick,
|
|
80
|
+
resetStickyPromptState,
|
|
81
|
+
updateStickyPromptHover,
|
|
82
|
+
} from "./sticky-prompt.ts";
|
|
79
83
|
|
|
80
84
|
type FrameToolRender = {
|
|
81
85
|
component: any;
|
|
@@ -308,10 +312,6 @@ function ensureFullscreenToolMouseMotion(tui: any): void {
|
|
|
308
312
|
releaseFullscreenToolMouseMotion(tui);
|
|
309
313
|
return;
|
|
310
314
|
}
|
|
311
|
-
// 面板改 scrollStepLines 后,下一帧渲染即同步(restore 仍按 original 恢复)。
|
|
312
|
-
if (typeof tui.wheelScrollLines === "number" && tui.wheelScrollLines !== config.scrollStepLines) {
|
|
313
|
-
tui.wheelScrollLines = config.scrollStepLines;
|
|
314
|
-
}
|
|
315
315
|
if (
|
|
316
316
|
!toolMouseInteractionActive() ||
|
|
317
317
|
tui.mouseEnabled === false ||
|
|
@@ -348,7 +348,6 @@ function releaseFullscreenToolMouseMotion(tui?: any): void {
|
|
|
348
348
|
}
|
|
349
349
|
|
|
350
350
|
const FULLSCREEN_VIEWPORT_PATCH = Symbol("ccstyle.fullscreen-viewport-patch");
|
|
351
|
-
const FULLSCREEN_WHEEL_SCROLL_ORIGINAL = Symbol("ccstyle.fullscreen-wheel-scroll-original");
|
|
352
351
|
|
|
353
352
|
/**
|
|
354
353
|
* diff 结果组件自带 remainder 行:声明存在时只有那一行是展开入口(正文里的同名字样不算);
|
|
@@ -445,9 +444,15 @@ function handleFullscreenToolClick(tui: any, packet: SgrMousePacket): boolean {
|
|
|
445
444
|
}
|
|
446
445
|
// 展开 round 卡内工具时,让 compact 的强制折叠放行它(非 round 内工具为空操作)。
|
|
447
446
|
if (isTool) markCompactRoundToolExpanded(component);
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
447
|
+
if (isAssistant) {
|
|
448
|
+
// compact 摘要行自己记展开前的视口(收起时还原跟随),所以它先展开再停跟随:
|
|
449
|
+
// 顺序反了快照会记下「未跟随」,收起时就交不回官方 follow。
|
|
450
|
+
component.setExpanded(true);
|
|
451
|
+
keepViewportOnExpand(tui);
|
|
452
|
+
} else {
|
|
453
|
+
keepViewportOnExpand(tui);
|
|
454
|
+
component.setExpanded(true);
|
|
455
|
+
}
|
|
451
456
|
clearPendingCollapsePress();
|
|
452
457
|
} else {
|
|
453
458
|
// 普通工具截断头 show-more:打开全量预览(不收起)。
|
|
@@ -487,10 +492,6 @@ function handleFullscreenToolClick(tui: any, packet: SgrMousePacket): boolean {
|
|
|
487
492
|
return true;
|
|
488
493
|
}
|
|
489
494
|
|
|
490
|
-
/**
|
|
491
|
-
* fullscreen 鼠标悬停:collapsed 卡 [click to show more] hint、
|
|
492
|
-
* expanded 卡截断头 show-more、回到底部按钮。motion 不 consume,官方链照常。
|
|
493
|
-
*/
|
|
494
495
|
/** 点到的组件和外层卡是否属于同一张 compact 回合面板。 */
|
|
495
496
|
function isSameExpandedRound(other: any, owner: any): boolean {
|
|
496
497
|
if (!owner || !isCompactAssistantComponent(other)) return false;
|
|
@@ -501,6 +502,7 @@ function isSameExpandedRound(other: any, owner: any): boolean {
|
|
|
501
502
|
/**
|
|
502
503
|
* 原地展开时停在当前滚动位置:transcript 跟随底部时,内容变高会把视口拖到底,
|
|
503
504
|
* 点击的行和它上方的外层面板被顶出屏幕。展开前关掉跟随,点击行留在原位。
|
|
505
|
+
* compact 摘要行同样适用:它的展开入口在 setExpanded 之后调用本函数(见调用点)。
|
|
504
506
|
*/
|
|
505
507
|
function keepViewportOnExpand(tui: any): void {
|
|
506
508
|
const view = tui.getPrimaryScrollView?.();
|
|
@@ -510,6 +512,10 @@ function keepViewportOnExpand(tui: any): void {
|
|
|
510
512
|
if (view.isFollowingEnd === false) setScrollButtonVisible(true);
|
|
511
513
|
}
|
|
512
514
|
|
|
515
|
+
/**
|
|
516
|
+
* fullscreen 鼠标悬停:collapsed 卡 [click to show more] hint、
|
|
517
|
+
* expanded 卡截断头 show-more、回到底部按钮。motion 不 consume,官方链照常。
|
|
518
|
+
*/
|
|
513
519
|
function handleFullscreenToolHover(tui: any, packet: SgrMousePacket): void {
|
|
514
520
|
if (!isSgrIdleMotion(packet)) return;
|
|
515
521
|
const layout = tui.currentLayout;
|
|
@@ -589,11 +595,6 @@ function patchFullscreenViewportInput(tui: any): void {
|
|
|
589
595
|
const proto = Object.getPrototypeOf(tui);
|
|
590
596
|
const original = proto?.handleViewportInput;
|
|
591
597
|
if (typeof original !== "function") return;
|
|
592
|
-
// 官方原生 routeWheel 已完整处理嵌套 ScrollView;只调整默认步进(config.scrollStepLines)。
|
|
593
|
-
if (typeof tui.wheelScrollLines === "number") {
|
|
594
|
-
tui[FULLSCREEN_WHEEL_SCROLL_ORIGINAL] = tui.wheelScrollLines;
|
|
595
|
-
tui.wheelScrollLines = config.scrollStepLines;
|
|
596
|
-
}
|
|
597
598
|
tui[FULLSCREEN_VIEWPORT_PATCH] = true;
|
|
598
599
|
tui.handleViewportInput = function (this: any, data: string) {
|
|
599
600
|
if (toolMouseInteractionActive() && tui.mode === "fullscreen") {
|
|
@@ -622,12 +623,17 @@ function patchFullscreenViewportInput(tui: any): void {
|
|
|
622
623
|
}
|
|
623
624
|
} else if (!isSgrLeftPress(packet) && !isSgrIdleMotion(packet))
|
|
624
625
|
clearPendingCollapsePressOnMove(packet);
|
|
626
|
+
if (isSgrLeftPress(packet) && handleStickyPromptClick(tui, packet)) {
|
|
627
|
+
return { consume: true };
|
|
628
|
+
}
|
|
625
629
|
if (isSgrLeftPress(packet) && handleFullscreenToolClick(tui, packet)) {
|
|
626
630
|
return { consume: true };
|
|
627
631
|
}
|
|
628
632
|
// 仅无按键移动走 hover;左键拖动(文本多选)放行官方选区,避免每像素命中+重绘。
|
|
629
633
|
if (isSgrIdleMotion(packet)) {
|
|
630
|
-
|
|
634
|
+
// 粘性行命中时不进工具 hover:同一行只能有一个高亮。
|
|
635
|
+
if (updateStickyPromptHover(tui, packet)) applyFullscreenHover(tui, null);
|
|
636
|
+
else handleFullscreenToolHover(tui, packet);
|
|
631
637
|
}
|
|
632
638
|
}
|
|
633
639
|
}
|
|
@@ -642,11 +648,6 @@ function restoreFullscreenViewportInput(tui: any): void {
|
|
|
642
648
|
if (typeof proto?.handleViewportInput === "function") {
|
|
643
649
|
tui.handleViewportInput = proto.handleViewportInput;
|
|
644
650
|
}
|
|
645
|
-
const originalWheelScrollLines = tui[FULLSCREEN_WHEEL_SCROLL_ORIGINAL];
|
|
646
|
-
if (typeof originalWheelScrollLines === "number") {
|
|
647
|
-
tui.wheelScrollLines = originalWheelScrollLines;
|
|
648
|
-
tui[FULLSCREEN_WHEEL_SCROLL_ORIGINAL] = undefined;
|
|
649
|
-
}
|
|
650
651
|
tui[FULLSCREEN_VIEWPORT_PATCH] = false;
|
|
651
652
|
}
|
|
652
653
|
|
|
@@ -1037,6 +1038,7 @@ export function resetToolHoverState(): void {
|
|
|
1037
1038
|
setHoveredCompactAssistant(null);
|
|
1038
1039
|
setScrollButtonVisible(false);
|
|
1039
1040
|
setScrollButtonHovered(false);
|
|
1041
|
+
resetStickyPromptState();
|
|
1040
1042
|
restoreOfficialScrollToEnd(getToolMouseTui());
|
|
1041
1043
|
releaseFullscreenToolMouseMotion(getToolMouseTui());
|
|
1042
1044
|
}
|