@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.
- package/README.md +1 -8
- package/node_modules/@herbertgao/pi-cc-extensions/README.en.md +76 -59
- package/node_modules/@herbertgao/pi-cc-extensions/README.md +76 -59
- package/node_modules/@herbertgao/pi-cc-extensions/assets/readme/preview.webp +0 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/config.ts +93 -34
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/panel.ts +346 -117
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/agent-summary/core.ts +6 -36
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/agent-summary/index.ts +2 -2
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/compact-thinking.ts +24 -29
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/context.ts +330 -360
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/reference/index.ts +56 -108
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/reference/session.ts +97 -15
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/reference/subagent.ts +80 -45
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/shell/flush-docked-bash.ts +36 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/shell/footer-layout.ts +229 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/shell/footer.ts +479 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/shell/startup-header.ts +92 -61
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/shell/working-message.ts +58 -38
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/index.ts +19 -3
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/compact-mode.ts +1080 -229
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/default-mode.ts +232 -259
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/index.ts +38 -48
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/markdown-enhance.ts +8 -2
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/hover.ts +2 -7
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/interaction.ts +277 -113
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/layout.ts +15 -6
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/packets.ts +18 -72
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/scroll.ts +61 -26
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/ansi-utils.ts +25 -57
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-component.ts +125 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-edit-render.ts +227 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-header.ts +136 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-highlight.ts +115 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-inline.ts +324 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-layout.ts +762 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-limits.ts +152 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-palette.ts +410 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-parse.ts +535 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-presentation.ts +2 -2
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-renderer.ts +21 -3219
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-text.ts +44 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-write-render.ts +568 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/index.ts +19 -18
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/line-width-safety.ts +2 -2
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/write-execution.ts +1 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/grouping.ts +142 -192
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/mcp-title.ts +39 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/{message-display.ts → tool/message-display.ts} +24 -90
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/names.ts +426 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/result.ts +90 -132
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/{show-more-hint.ts → tool/show-more-hint.ts} +10 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/transcript-refresh.ts +8 -26
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/utils/ansi-color.ts +44 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/utils/ansi-text.ts +76 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/utils/component-tree.ts +34 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/utils/format.ts +28 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/utils/fullscreen-detect.ts +51 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/utils/patch-keys.ts +124 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/utils/sgr-mouse.ts +70 -0
- package/node_modules/@herbertgao/pi-cc-extensions/package.json +7 -7
- package/package.json +3 -7
- package/node_modules/@herbertgao/pi-cc-extensions/assets/readme/hero.en.svg +0 -101
- package/node_modules/@herbertgao/pi-cc-extensions/assets/readme/hero.svg +0 -101
- package/node_modules/@herbertgao/pi-cc-extensions/assets/readme/welcome.webp +0 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/render-utils.ts +0 -5
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/types.ts +0 -30
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/write-display-utils.ts +0 -12
- package/node_modules/pi-footer/CHANGELOG.md +0 -145
- package/node_modules/pi-footer/LICENSE +0 -21
- package/node_modules/pi-footer/README.md +0 -354
- package/node_modules/pi-footer/package.json +0 -68
- package/node_modules/pi-footer/src/cache.ts +0 -106
- package/node_modules/pi-footer/src/colors.ts +0 -237
- package/node_modules/pi-footer/src/config.ts +0 -202
- package/node_modules/pi-footer/src/event-widgets.ts +0 -41
- package/node_modules/pi-footer/src/extension-statuses.ts +0 -102
- package/node_modules/pi-footer/src/git.ts +0 -135
- package/node_modules/pi-footer/src/index.ts +0 -268
- package/node_modules/pi-footer/src/metrics.ts +0 -141
- package/node_modules/pi-footer/src/presets.ts +0 -383
- package/node_modules/pi-footer/src/render.ts +0 -114
- package/node_modules/pi-footer/src/separators.ts +0 -52
- package/node_modules/pi-footer/src/types.ts +0 -122
- package/node_modules/pi-footer/src/ui/color-level-confirm.ts +0 -22
- package/node_modules/pi-footer/src/ui/color-options.ts +0 -195
- package/node_modules/pi-footer/src/ui/config-lifecycle.ts +0 -61
- package/node_modules/pi-footer/src/ui/edit-colors.ts +0 -13
- package/node_modules/pi-footer/src/ui/events.ts +0 -35
- package/node_modules/pi-footer/src/ui/extension-status-picker.ts +0 -60
- package/node_modules/pi-footer/src/ui/extension-statuses.ts +0 -73
- package/node_modules/pi-footer/src/ui/fields.ts +0 -252
- package/node_modules/pi-footer/src/ui/global-menu.ts +0 -126
- package/node_modules/pi-footer/src/ui/helpers.ts +0 -44
- package/node_modules/pi-footer/src/ui/layout.ts +0 -17
- package/node_modules/pi-footer/src/ui/line-list.ts +0 -19
- package/node_modules/pi-footer/src/ui/model.ts +0 -64
- package/node_modules/pi-footer/src/ui/navigation.ts +0 -29
- package/node_modules/pi-footer/src/ui/option-edit.ts +0 -93
- package/node_modules/pi-footer/src/ui/overlay-render.ts +0 -103
- package/node_modules/pi-footer/src/ui/screen-context.ts +0 -18
- package/node_modules/pi-footer/src/ui/screen-controller.ts +0 -27
- package/node_modules/pi-footer/src/ui/screen-render.ts +0 -32
- package/node_modules/pi-footer/src/ui/screen-state.ts +0 -20
- package/node_modules/pi-footer/src/ui/screen.ts +0 -243
- package/node_modules/pi-footer/src/ui/screens/add-widget.ts +0 -92
- package/node_modules/pi-footer/src/ui/screens/confirm-exit.ts +0 -52
- package/node_modules/pi-footer/src/ui/screens/controller.ts +0 -12
- package/node_modules/pi-footer/src/ui/screens/edit-colors.ts +0 -68
- package/node_modules/pi-footer/src/ui/screens/edit-widget.ts +0 -115
- package/node_modules/pi-footer/src/ui/screens/extension-status-row.ts +0 -61
- package/node_modules/pi-footer/src/ui/screens/global.ts +0 -75
- package/node_modules/pi-footer/src/ui/screens/line-list.ts +0 -108
- package/node_modules/pi-footer/src/ui/screens/main.ts +0 -99
- package/node_modules/pi-footer/src/ui/screens/terminal.ts +0 -121
- package/node_modules/pi-footer/src/ui/screens/widget-list.ts +0 -154
- package/node_modules/pi-footer/src/ui/terminal-menu.ts +0 -32
- package/node_modules/pi-footer/src/ui/theme.ts +0 -48
- package/node_modules/pi-footer/src/ui/title-bar.ts +0 -100
- package/node_modules/pi-footer/src/ui/widget-actions.ts +0 -76
- package/node_modules/pi-footer/src/ui.ts +0 -66
- package/node_modules/pi-footer/src/widgets/context.ts +0 -28
- package/node_modules/pi-footer/src/widgets/core/active-tools.ts +0 -17
- package/node_modules/pi-footer/src/widgets/core/context-window.ts +0 -24
- package/node_modules/pi-footer/src/widgets/core/cwd-basename.ts +0 -19
- package/node_modules/pi-footer/src/widgets/core/cwd.ts +0 -108
- package/node_modules/pi-footer/src/widgets/core/event.ts +0 -34
- package/node_modules/pi-footer/src/widgets/core/external-status.ts +0 -102
- package/node_modules/pi-footer/src/widgets/core/model-provider.ts +0 -20
- package/node_modules/pi-footer/src/widgets/core/model.ts +0 -35
- package/node_modules/pi-footer/src/widgets/core/provider.ts +0 -17
- package/node_modules/pi-footer/src/widgets/core/session-name.ts +0 -17
- package/node_modules/pi-footer/src/widgets/core/text-verbosity.ts +0 -17
- package/node_modules/pi-footer/src/widgets/core/thinking-level.ts +0 -17
- package/node_modules/pi-footer/src/widgets/git/ahead-behind.ts +0 -17
- package/node_modules/pi-footer/src/widgets/git/branch.ts +0 -81
- package/node_modules/pi-footer/src/widgets/git/clean.ts +0 -19
- package/node_modules/pi-footer/src/widgets/git/deletions.ts +0 -17
- package/node_modules/pi-footer/src/widgets/git/diff.ts +0 -38
- package/node_modules/pi-footer/src/widgets/git/insertions.ts +0 -17
- package/node_modules/pi-footer/src/widgets/git/remote.ts +0 -17
- package/node_modules/pi-footer/src/widgets/git/root.ts +0 -17
- package/node_modules/pi-footer/src/widgets/git/sha.ts +0 -17
- package/node_modules/pi-footer/src/widgets/git/staged.ts +0 -17
- package/node_modules/pi-footer/src/widgets/git/status.ts +0 -19
- package/node_modules/pi-footer/src/widgets/git/unstaged.ts +0 -17
- package/node_modules/pi-footer/src/widgets/git/untracked.ts +0 -17
- package/node_modules/pi-footer/src/widgets/instance.ts +0 -118
- package/node_modules/pi-footer/src/widgets/layout/custom-text.ts +0 -18
- package/node_modules/pi-footer/src/widgets/layout/flex-separator.ts +0 -32
- package/node_modules/pi-footer/src/widgets/layout/separator.ts +0 -57
- package/node_modules/pi-footer/src/widgets/layout/spacer.ts +0 -31
- package/node_modules/pi-footer/src/widgets/options.ts +0 -122
- package/node_modules/pi-footer/src/widgets/project/runtime.ts +0 -361
- package/node_modules/pi-footer/src/widgets/registry.ts +0 -223
- package/node_modules/pi-footer/src/widgets/session/assistant-messages.ts +0 -17
- package/node_modules/pi-footer/src/widgets/session/compactions.ts +0 -17
- package/node_modules/pi-footer/src/widgets/session/elapsed.ts +0 -18
- package/node_modules/pi-footer/src/widgets/session/last-activity.ts +0 -18
- package/node_modules/pi-footer/src/widgets/session/messages.ts +0 -19
- package/node_modules/pi-footer/src/widgets/session/session-id.ts +0 -17
- package/node_modules/pi-footer/src/widgets/session/session-start.ts +0 -18
- package/node_modules/pi-footer/src/widgets/session/tool-results.ts +0 -17
- package/node_modules/pi-footer/src/widgets/session/total-messages.ts +0 -19
- package/node_modules/pi-footer/src/widgets/session/total-time.ts +0 -18
- package/node_modules/pi-footer/src/widgets/session/user-messages.ts +0 -17
- package/node_modules/pi-footer/src/widgets/store.ts +0 -26
- package/node_modules/pi-footer/src/widgets/tokens/cache-hit-rate.ts +0 -55
- package/node_modules/pi-footer/src/widgets/tokens/cache-read.ts +0 -18
- package/node_modules/pi-footer/src/widgets/tokens/cache-write.ts +0 -18
- package/node_modules/pi-footer/src/widgets/tokens/context-bar.ts +0 -108
- package/node_modules/pi-footer/src/widgets/tokens/context-length.ts +0 -26
- package/node_modules/pi-footer/src/widgets/tokens/context-remaining.ts +0 -29
- package/node_modules/pi-footer/src/widgets/tokens/context.ts +0 -29
- package/node_modules/pi-footer/src/widgets/tokens/cost.ts +0 -51
- package/node_modules/pi-footer/src/widgets/tokens/input-speed.ts +0 -25
- package/node_modules/pi-footer/src/widgets/tokens/input-tokens.ts +0 -18
- package/node_modules/pi-footer/src/widgets/tokens/output-speed.ts +0 -25
- package/node_modules/pi-footer/src/widgets/tokens/output-tokens.ts +0 -18
- package/node_modules/pi-footer/src/widgets/tokens/tokens.ts +0 -20
- package/node_modules/pi-footer/src/widgets/tokens/total-speed.ts +0 -25
- package/node_modules/pi-footer/src/widgets/tokens/total-tokens.ts +0 -18
- package/node_modules/pi-footer/src/widgets/types.ts +0 -181
- package/node_modules/pi-footer/src/widgets/utils/colors.ts +0 -11
- package/node_modules/pi-footer/src/widgets/utils/context.ts +0 -112
- package/node_modules/pi-footer/src/widgets/utils/session.ts +0 -19
- package/node_modules/pi-footer/src/widgets/utils/token-format.ts +0 -78
|
@@ -7,16 +7,19 @@
|
|
|
7
7
|
import { ToolExecutionComponent } from "@earendil-works/pi-coding-agent";
|
|
8
8
|
import { Text, truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
|
|
9
9
|
import { config, getToolDisplayConfig, type CompactStyleMode } from "../config/config.ts";
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
COMPONENT_TOOL_RENDER_MODE,
|
|
12
|
+
GLOBAL_TOOL_RENDER_PATCH,
|
|
13
|
+
patchRegistry,
|
|
14
|
+
TOOL_EXPANDED_BACKGROUND_PATCH,
|
|
15
|
+
} from "../utils/patch-keys.ts";
|
|
16
|
+
import { isToolCallHovered } from "./mouse/hover.ts";
|
|
11
17
|
import {
|
|
12
18
|
countLines,
|
|
13
|
-
fitToolCallSummary,
|
|
14
19
|
hasExpandableDetail,
|
|
15
20
|
insetComponent,
|
|
16
21
|
isToolExpanded,
|
|
17
|
-
oneLine,
|
|
18
22
|
outputLineCount,
|
|
19
|
-
pathSummary,
|
|
20
23
|
pendingIcon,
|
|
21
24
|
renderCollapsedToolResultToWidth,
|
|
22
25
|
renderExpandedToolResult,
|
|
@@ -27,27 +30,24 @@ import {
|
|
|
27
30
|
textFromResult,
|
|
28
31
|
toolIconColor,
|
|
29
32
|
toolViewportWidth,
|
|
30
|
-
type ToolCallSummary,
|
|
31
33
|
} from "./tool/result.ts";
|
|
32
|
-
import {
|
|
34
|
+
import { oneLine } from "../utils/format.ts";
|
|
35
|
+
import { showMoreHintText } from "./tool/show-more-hint.ts";
|
|
36
|
+
import { countWriteDiffStats } from "./tool/diff/diff-renderer.ts";
|
|
33
37
|
import { renderRichToolResult, type WriteExecutionMetadataStore } from "./tool/diff/index.ts";
|
|
34
|
-
import { getMessageDisplayTheme } from "./message-display.ts";
|
|
38
|
+
import { getMessageDisplayTheme } from "./tool/message-display.ts";
|
|
39
|
+
import { mcpToolTitle } from "./tool/mcp-title.ts";
|
|
40
|
+
import {
|
|
41
|
+
fitToolCallSummary,
|
|
42
|
+
humanizeToolLabel,
|
|
43
|
+
renderToolSummary,
|
|
44
|
+
toolCallSummary,
|
|
45
|
+
} from "./tool/names.ts";
|
|
35
46
|
|
|
36
47
|
// 成功勾:亮绿 truecolor(与 message-display 一致)
|
|
37
48
|
const BRIGHT_GREEN = "\x1b[38;2;80;220;100m";
|
|
38
49
|
const ANSI_FG_RESET = "\x1b[39m";
|
|
39
50
|
|
|
40
|
-
const GLOBAL_TOOL_RENDER_PATCH = Symbol.for("pi.ccstyle.global-tool-render-patch");
|
|
41
|
-
const COMPONENT_TOOL_RENDER_MODE = Symbol.for("pi.ccstyle.component-tool-render-mode");
|
|
42
|
-
const COMPONENT_TOOL_SELF_SHELL_MODE = Symbol.for("pi.ccstyle.component-tool-self-shell-mode");
|
|
43
|
-
const TOOL_EXPANDED_BACKGROUND_PATCH = Symbol.for("pi.ccstyle.tool-expanded-background-patch");
|
|
44
|
-
|
|
45
|
-
const AGENT_FAMILY_TOOL_NAMES = new Set([
|
|
46
|
-
"Agent",
|
|
47
|
-
"Agents",
|
|
48
|
-
"get_subagent_result",
|
|
49
|
-
"steer_subagent",
|
|
50
|
-
]);
|
|
51
51
|
// pi-subagents 等扩展为 Agent 提供专用渲染器,ccstyle 必须保留。
|
|
52
52
|
const DEDICATED_RENDERER_TOOLS = new Set(["Agent"]);
|
|
53
53
|
|
|
@@ -64,23 +64,32 @@ type ToolRenderMethods = {
|
|
|
64
64
|
getResultRenderer: (...args: any[]) => any;
|
|
65
65
|
};
|
|
66
66
|
|
|
67
|
+
type ToolPaintHit = {
|
|
68
|
+
width: number;
|
|
69
|
+
expanded: boolean;
|
|
70
|
+
isPartial: boolean;
|
|
71
|
+
result: unknown;
|
|
72
|
+
args: unknown;
|
|
73
|
+
callHover: boolean;
|
|
74
|
+
ioHover: string | null;
|
|
75
|
+
lines: string[];
|
|
76
|
+
};
|
|
77
|
+
|
|
67
78
|
type GlobalToolRenderPatch = {
|
|
68
79
|
version: 2;
|
|
69
80
|
prototype: any;
|
|
70
|
-
owner: object;
|
|
71
81
|
active: boolean;
|
|
72
|
-
enabled: () => boolean;
|
|
73
82
|
mode: () => CompactStyleMode;
|
|
74
83
|
wrap: (tool: any) => any;
|
|
75
84
|
byDefinition: WeakMap<object, any>;
|
|
76
85
|
byName: Map<string, any>;
|
|
77
86
|
downstream: ToolRenderMethods;
|
|
78
87
|
installed: ToolRenderMethods;
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
88
|
+
originalRender?: (width: number) => string[];
|
|
89
|
+
originalInvalidate?: () => void;
|
|
90
|
+
renderPaint?: (width: number) => string[];
|
|
91
|
+
invalidatePaint?: () => void;
|
|
92
|
+
paintCache?: WeakMap<object, ToolPaintHit>;
|
|
84
93
|
};
|
|
85
94
|
|
|
86
95
|
type ToolExpandedBackgroundPatch = {
|
|
@@ -91,6 +100,8 @@ type ToolExpandedBackgroundPatch = {
|
|
|
91
100
|
dispose: () => void;
|
|
92
101
|
};
|
|
93
102
|
|
|
103
|
+
/** rich diff 的两个入口(本处与 compact 的 paintCompactEditWrite)都靠 renderRichToolResult
|
|
104
|
+
* 返回 undefined 让位,这里只判断模式与工具名,避免多一个可能与让位不一致的 gate。 */
|
|
94
105
|
export function shouldRenderRichDiff(
|
|
95
106
|
mode: CompactStyleMode,
|
|
96
107
|
toolName: string,
|
|
@@ -99,25 +110,6 @@ export function shouldRenderRichDiff(
|
|
|
99
110
|
return mode === "on" && !isError && (toolName === "edit" || toolName === "write");
|
|
100
111
|
}
|
|
101
112
|
|
|
102
|
-
export function isMcpToolDefinition(definition: any, toolName: string): boolean {
|
|
103
|
-
const label = typeof definition?.label === "string" ? definition.label.trim() : "";
|
|
104
|
-
if (/^MCP(?::|$)/i.test(label)) return true;
|
|
105
|
-
if (toolName === "mcp" || /^mcp[_:-]|[_:-]mcp[_:-]/i.test(toolName)) return true;
|
|
106
|
-
if (label) return false;
|
|
107
|
-
const description = typeof definition?.description === "string" ? definition.description : "";
|
|
108
|
-
return /\bModel Context Protocol\b/i.test(description);
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
export function humanizeMcpToolName(toolName: string): string {
|
|
112
|
-
const words = toolName
|
|
113
|
-
.replace(/^mcp(?:[_:-]+)+/i, "")
|
|
114
|
-
.split(/[_:-]+/)
|
|
115
|
-
.filter(Boolean);
|
|
116
|
-
return words.length
|
|
117
|
-
? words.map((word) => word[0]!.toUpperCase() + word.slice(1)).join(" ")
|
|
118
|
-
: "MCP";
|
|
119
|
-
}
|
|
120
|
-
|
|
121
113
|
/** 排除名单内且自带 renderer 的工具保留原渲染。 */
|
|
122
114
|
export function preservesOriginalRenderer(
|
|
123
115
|
extensionDefinition: any,
|
|
@@ -143,97 +135,6 @@ function renderDefault(tool: any, slot: "renderCall" | "renderResult", args: any
|
|
|
143
135
|
return new Text(fallback, 0, 0);
|
|
144
136
|
}
|
|
145
137
|
|
|
146
|
-
function humanizeToolLabel(label: string): string {
|
|
147
|
-
return label
|
|
148
|
-
.replace(/([a-z0-9])([A-Z])/g, "$1 $2")
|
|
149
|
-
.replace(/[_-]+/g, " ")
|
|
150
|
-
.replace(/\b\w/g, (char) => char.toUpperCase());
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
function singleToolCallSummary(
|
|
154
|
-
toolName: string,
|
|
155
|
-
label: string,
|
|
156
|
-
args: any,
|
|
157
|
-
cwd?: string,
|
|
158
|
-
): ToolCallSummary {
|
|
159
|
-
const title = label === toolName ? humanizeToolLabel(label) : label;
|
|
160
|
-
if (!args || typeof args !== "object") return { main: title, detail: "" };
|
|
161
|
-
const name = toolName.toLowerCase();
|
|
162
|
-
const value = (fallback: string, ...keys: string[]) => {
|
|
163
|
-
const found = keys.map((key) => args[key]).find((item) => typeof item === "string" && item);
|
|
164
|
-
return `${title} ${oneLine(found || fallback)}`;
|
|
165
|
-
};
|
|
166
|
-
if (AGENT_FAMILY_TOOL_NAMES.has(toolName) && args.agent_id) {
|
|
167
|
-
return { main: `${title} ${oneLine(args.agent_id)}`, detail: "" };
|
|
168
|
-
}
|
|
169
|
-
// Agents 走 ccstyle wrapper;Agent 保留专用渲染器。
|
|
170
|
-
if (name === "agents") {
|
|
171
|
-
return {
|
|
172
|
-
main: value("launch agents", "description", "prompt"),
|
|
173
|
-
detail: "",
|
|
174
|
-
};
|
|
175
|
-
}
|
|
176
|
-
if (name === "skill") return { main: value("run skill", "name"), detail: "" };
|
|
177
|
-
if (name === "enterplanmode" || name === "enter_plan_mode") {
|
|
178
|
-
return { main: `${title} enable read-only planning`, detail: "" };
|
|
179
|
-
}
|
|
180
|
-
if (name === "exitplanmode" || name === "exit_plan_mode") {
|
|
181
|
-
return { main: `${title} present plan`, detail: "" };
|
|
182
|
-
}
|
|
183
|
-
if (name === "taskcreate") return { main: value("create task", "subject"), detail: "" };
|
|
184
|
-
if (name === "tasklist") return { main: `${title} task list`, detail: "" };
|
|
185
|
-
if (name === "taskget" || name === "taskupdate") {
|
|
186
|
-
return { main: value("task", "taskId", "task_id"), detail: "" };
|
|
187
|
-
}
|
|
188
|
-
if (name === "taskoutput" || name === "taskstop") {
|
|
189
|
-
return { main: value("background task", "task_id", "taskId"), detail: "" };
|
|
190
|
-
}
|
|
191
|
-
if (name === "taskexecute") {
|
|
192
|
-
const ids = Array.isArray(args.task_ids)
|
|
193
|
-
? args.task_ids
|
|
194
|
-
: Array.isArray(args.taskIds)
|
|
195
|
-
? args.taskIds
|
|
196
|
-
: [];
|
|
197
|
-
const summary = ids.length
|
|
198
|
-
? `${ids[0]}${ids.length > 1 ? ` (+${ids.length - 1} tasks)` : ""}`
|
|
199
|
-
: "start tasks";
|
|
200
|
-
return { main: `${title} ${summary}`, detail: "" };
|
|
201
|
-
}
|
|
202
|
-
if (toolName === "read") {
|
|
203
|
-
const details = [
|
|
204
|
-
args.offset !== undefined ? `offset=${args.offset}` : "",
|
|
205
|
-
args.limit !== undefined ? `limit=${args.limit}` : "",
|
|
206
|
-
].filter(Boolean);
|
|
207
|
-
const detail = details.length ? ` (${details.join(", ")})` : "";
|
|
208
|
-
if (typeof args.path === "string" && args.path) {
|
|
209
|
-
return pathSummary(title, args.path, cwd, detail);
|
|
210
|
-
}
|
|
211
|
-
return { main: title, detail };
|
|
212
|
-
}
|
|
213
|
-
const preferredPath = args.path ?? args.file_path;
|
|
214
|
-
if (typeof preferredPath === "string" && preferredPath) {
|
|
215
|
-
return pathSummary(title, preferredPath, cwd);
|
|
216
|
-
}
|
|
217
|
-
const preferred =
|
|
218
|
-
args.command ??
|
|
219
|
-
args.query ??
|
|
220
|
-
args.question ??
|
|
221
|
-
args.pattern ??
|
|
222
|
-
args.url ??
|
|
223
|
-
args.name ??
|
|
224
|
-
args.tool_use_id ??
|
|
225
|
-
args.toolCallId ??
|
|
226
|
-
args.id ??
|
|
227
|
-
args.message;
|
|
228
|
-
return {
|
|
229
|
-
main:
|
|
230
|
-
preferred !== undefined && preferred !== null && typeof preferred !== "object"
|
|
231
|
-
? `${title} ${oneLine(preferred)}`
|
|
232
|
-
: title,
|
|
233
|
-
detail: "",
|
|
234
|
-
};
|
|
235
|
-
}
|
|
236
|
-
|
|
237
138
|
type ParsedTask = { id: string; status: string; subject: string };
|
|
238
139
|
|
|
239
140
|
function parseTaskList(text: string): ParsedTask[] {
|
|
@@ -277,11 +178,16 @@ function renderExpandedTaskResult(
|
|
|
277
178
|
: task.status === "in_progress"
|
|
278
179
|
? "warning"
|
|
279
180
|
: "muted";
|
|
280
|
-
return
|
|
181
|
+
return `${theme.fg("accent", `#${task.id}`)} ${theme.fg(color, task.status)} ${theme.fg("dim", task.subject)}`;
|
|
281
182
|
});
|
|
282
183
|
if (tasks.length > rows.length)
|
|
283
|
-
rows.push(theme.fg("muted",
|
|
284
|
-
|
|
184
|
+
rows.push(theme.fg("muted", `… ${tasks.length - rows.length} more tasks`));
|
|
185
|
+
// 贴左:外层展开卡片 Box(1,1) 提供 1 格 padding
|
|
186
|
+
return new Text(
|
|
187
|
+
`↳ ${theme.fg("muted", taskListSummary(tasks))}\n${rows.map((r) => ` ${r}`).join("\n")}`,
|
|
188
|
+
0,
|
|
189
|
+
0,
|
|
190
|
+
);
|
|
285
191
|
}
|
|
286
192
|
const line = text.trim();
|
|
287
193
|
if (!line || line.includes("\n")) return undefined;
|
|
@@ -299,7 +205,7 @@ function renderExpandedTaskResult(
|
|
|
299
205
|
} else if (toolName === "TaskStop") {
|
|
300
206
|
formatted = `${theme.fg("success", "Stopped")} ${theme.fg("muted", line)}`;
|
|
301
207
|
}
|
|
302
|
-
return formatted ? new Text(
|
|
208
|
+
return formatted ? new Text(`↳ ${formatted}`, 0, 0) : undefined;
|
|
303
209
|
}
|
|
304
210
|
|
|
305
211
|
/** 用 ccstyle call/result 包装任意工具定义。 */
|
|
@@ -308,15 +214,16 @@ function createCcstyleTool(
|
|
|
308
214
|
writeExecutionMetadata: WriteExecutionMetadataStore,
|
|
309
215
|
): any {
|
|
310
216
|
const toolName = originalTool.name;
|
|
311
|
-
const label =
|
|
312
|
-
|
|
313
|
-
|
|
217
|
+
const label = originalTool.label || toolName;
|
|
218
|
+
const defaultTitle = label === toolName ? humanizeToolLabel(label) : label;
|
|
219
|
+
// MCP 工具直接用 adapter 暴露的真实工具名,不做人性化
|
|
220
|
+
const title = mcpToolTitle({ toolName, definition: originalTool }) ?? defaultTitle;
|
|
314
221
|
|
|
315
222
|
return {
|
|
316
223
|
...originalTool,
|
|
317
224
|
renderShell: "self",
|
|
318
225
|
renderCall(args: any, theme: any, context: any) {
|
|
319
|
-
if (config.mode
|
|
226
|
+
if (config.mode === "off") {
|
|
320
227
|
return renderDefault(originalTool, "renderCall", [args, theme, context], String(toolName));
|
|
321
228
|
}
|
|
322
229
|
|
|
@@ -324,31 +231,71 @@ function createCcstyleTool(
|
|
|
324
231
|
const isPending =
|
|
325
232
|
visualState === "pending" ||
|
|
326
233
|
(!visualState && (context?.isPartial || context?.executionStarted));
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
const
|
|
234
|
+
const animating = isPending && Boolean(context?.executionStarted);
|
|
235
|
+
if (animating) scheduleAnimation(context, { light: true });
|
|
236
|
+
const settledRawIcon = isPending ? "" : settledIcon(toolName, visualState);
|
|
237
|
+
const settledIconStyled =
|
|
330
238
|
visualState === "success"
|
|
331
|
-
? `${BRIGHT_GREEN}${
|
|
332
|
-
: theme.fg(toolIconColor(context),
|
|
333
|
-
|
|
239
|
+
? `${BRIGHT_GREEN}${settledRawIcon}${ANSI_FG_RESET}`
|
|
240
|
+
: theme.fg(toolIconColor(context), settledRawIcon);
|
|
241
|
+
// 逐帧 spinner:帧在 render() 内取,动画定时器只需 requestRender,
|
|
242
|
+
// 不再每次 tick 走 updateDisplay 把整张卡重建一遍。
|
|
243
|
+
const pendingIconStyled = () => theme.fg(toolIconColor(context), pendingIcon(toolName));
|
|
244
|
+
const summary = toolCallSummary(toolName, args, {
|
|
245
|
+
title,
|
|
246
|
+
variant: "default",
|
|
247
|
+
cwd: context?.cwd,
|
|
248
|
+
});
|
|
249
|
+
let writeStatsText = "";
|
|
250
|
+
let writeStatsStyled = "";
|
|
251
|
+
if (toolName === "write" && visualState === "success") {
|
|
252
|
+
const meta = writeExecutionMetadata.get(context?.toolCallId);
|
|
253
|
+
const stats = countWriteDiffStats(
|
|
254
|
+
typeof args?.content === "string" ? args.content : undefined,
|
|
255
|
+
meta?.previousContent,
|
|
256
|
+
meta?.fileExistedBeforeWrite,
|
|
257
|
+
);
|
|
258
|
+
if (stats) {
|
|
259
|
+
writeStatsText = ` (+${stats.added} -${stats.removed})`;
|
|
260
|
+
writeStatsStyled = ` ${theme.fg("dim", "(")}${theme.fg("success", `+${stats.added}`)} ${theme.fg("error", `-${stats.removed}`)}${theme.fg("dim", ")")}`;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
const extraText = writeStatsText || summary.detail;
|
|
264
|
+
const extraStyled = writeStatsStyled || theme.fg("dim", summary.detail);
|
|
334
265
|
let cachedWidth: number | undefined;
|
|
335
266
|
let cachedLine: string | undefined;
|
|
267
|
+
let cachedIcon: string | undefined;
|
|
268
|
+
const expanded = Boolean(context?.expanded);
|
|
336
269
|
return {
|
|
337
270
|
render(width: number) {
|
|
338
|
-
|
|
271
|
+
// 轻量 tick 只会 requestRender,靠这里续期,动画才能自维持。
|
|
272
|
+
if (animating) scheduleAnimation(context, { light: true });
|
|
273
|
+
const icon = isPending ? pendingIconStyled() : settledIconStyled;
|
|
274
|
+
if (cachedLine !== undefined && cachedWidth === width && cachedIcon === icon) {
|
|
275
|
+
return [cachedLine];
|
|
276
|
+
}
|
|
339
277
|
const viewportWidth = toolViewportWidth(width);
|
|
340
|
-
|
|
341
|
-
const
|
|
278
|
+
// 展开态贴左(外层 Box 已 pad 1);折叠 self-shell 保留 1 格前导空格
|
|
279
|
+
const lead = expanded ? "" : " ";
|
|
280
|
+
const callWidth = Math.max(
|
|
281
|
+
0,
|
|
282
|
+
viewportWidth - visibleWidth(icon) - 1 - (expanded ? 0 : 1),
|
|
283
|
+
);
|
|
284
|
+
const mainWidth = Math.max(0, callWidth - visibleWidth(extraText));
|
|
342
285
|
cachedWidth = width;
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
286
|
+
cachedIcon = icon;
|
|
287
|
+
// 路径按最终可用宽度中间截断,避免整行二次截断隐藏文件名。
|
|
288
|
+
cachedLine = `${lead}${icon} ${renderToolSummary(summary, mainWidth, theme.fg.bind(theme))}${extraStyled}`;
|
|
289
|
+
return [truncateToWidth(cachedLine, viewportWidth, "")];
|
|
290
|
+
},
|
|
291
|
+
invalidate() {
|
|
292
|
+
cachedLine = undefined;
|
|
293
|
+
cachedIcon = undefined;
|
|
346
294
|
},
|
|
347
|
-
invalidate() {},
|
|
348
295
|
};
|
|
349
296
|
},
|
|
350
297
|
renderResult(result: any, options: any, theme: any, context: any) {
|
|
351
|
-
if (config.mode
|
|
298
|
+
if (config.mode === "off") {
|
|
352
299
|
return renderDefault(
|
|
353
300
|
originalTool,
|
|
354
301
|
"renderResult",
|
|
@@ -357,13 +304,15 @@ function createCcstyleTool(
|
|
|
357
304
|
);
|
|
358
305
|
}
|
|
359
306
|
|
|
307
|
+
const expanded = isToolExpanded(options, context);
|
|
360
308
|
if (options?.isPartial) {
|
|
361
|
-
|
|
309
|
+
// 展开态贴左(Box 提供 1 格 pad);折叠态保持 3 格对齐标题
|
|
310
|
+
const pending = expanded ? "↳ Pending…" : " ↳ Pending…";
|
|
311
|
+
return new Text(theme.fg("muted", pending), 0, 0);
|
|
362
312
|
}
|
|
363
313
|
|
|
364
314
|
const isError = options?.isError || context?.isError;
|
|
365
315
|
setToolVisualState(context, isError ? "error" : "success");
|
|
366
|
-
const expanded = isToolExpanded(options, context);
|
|
367
316
|
const toolCallId = context?.toolCallId;
|
|
368
317
|
if (shouldRenderRichDiff(config.mode, toolName, Boolean(isError))) {
|
|
369
318
|
// getter 保证 Diff indicator / wrap / limits 下次绘制即更新
|
|
@@ -381,7 +330,8 @@ function createCcstyleTool(
|
|
|
381
330
|
writeExecutionMetadata,
|
|
382
331
|
getToolDisplayConfig,
|
|
383
332
|
);
|
|
384
|
-
|
|
333
|
+
// 展开态由 Box(1,1) 提供内边距;折叠态 inset 一级缩进
|
|
334
|
+
if (richResult) return expanded ? richResult : insetComponent(richResult);
|
|
385
335
|
}
|
|
386
336
|
|
|
387
337
|
const text = textFromResult(result, expanded);
|
|
@@ -398,7 +348,8 @@ function createCcstyleTool(
|
|
|
398
348
|
? taskListSummary(tasks)
|
|
399
349
|
: isError
|
|
400
350
|
? text
|
|
401
|
-
?
|
|
351
|
+
? // 72 与原 result.ts 默认一致,保持错误摘要截断宽度。
|
|
352
|
+
oneLine(text, 72)
|
|
402
353
|
: "Failed"
|
|
403
354
|
: outputLines
|
|
404
355
|
? `${outputLines} ${lineWord} ${action}`
|
|
@@ -416,6 +367,7 @@ function createCcstyleTool(
|
|
|
416
367
|
context?.lastComponent,
|
|
417
368
|
args,
|
|
418
369
|
context,
|
|
370
|
+
true, // mode=on:贴左,由外层 Box(1,1) 提供 1 格 padding
|
|
419
371
|
);
|
|
420
372
|
}
|
|
421
373
|
if (context?.state) context.state.ccstyleIoView = undefined;
|
|
@@ -466,19 +418,15 @@ function shouldGloballyStyleTool(component: any, patch: GlobalToolRenderPatch):
|
|
|
466
418
|
const builtInDefinition = component.builtInToolDefinition;
|
|
467
419
|
const definition = extensionDefinition ?? builtInDefinition;
|
|
468
420
|
const toolName = String(component.toolName || definition?.name || "");
|
|
421
|
+
// compact 也复用同一套 ccstyle call/result,避免折叠态工具卡回落到 Pi 原生样式。
|
|
469
422
|
const useCcstyle =
|
|
470
|
-
patch.mode()
|
|
423
|
+
patch.mode() !== "off" &&
|
|
471
424
|
!DEDICATED_RENDERER_TOOLS.has(toolName) &&
|
|
472
425
|
!preservesOriginalRenderer(extensionDefinition, toolName, builtInDefinition);
|
|
473
426
|
component[COMPONENT_TOOL_RENDER_MODE] = useCcstyle;
|
|
474
427
|
return useCcstyle;
|
|
475
428
|
}
|
|
476
429
|
|
|
477
|
-
function shouldUseSelfShell(component: any, _patch: GlobalToolRenderPatch): boolean {
|
|
478
|
-
component[COMPONENT_TOOL_SELF_SHELL_MODE] = false;
|
|
479
|
-
return false;
|
|
480
|
-
}
|
|
481
|
-
|
|
482
430
|
function getGloballyStyledTool(component: any, patch: GlobalToolRenderPatch): any {
|
|
483
431
|
const definition = component.toolDefinition ?? component.builtInToolDefinition;
|
|
484
432
|
if (definition && typeof definition === "object") {
|
|
@@ -516,107 +464,88 @@ function isOwnershipAwarePatch(value: any): value is GlobalToolRenderPatch {
|
|
|
516
464
|
);
|
|
517
465
|
}
|
|
518
466
|
|
|
519
|
-
function
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
return (
|
|
524
|
-
source.includes(downstreamField) &&
|
|
525
|
-
(source.includes("shouldGloballyStyleTool") ||
|
|
526
|
-
source.includes("shouldUseSelfShell") ||
|
|
527
|
-
source.includes("getGloballyStyledTool"))
|
|
528
|
-
);
|
|
529
|
-
} catch {
|
|
530
|
-
return false;
|
|
531
|
-
}
|
|
532
|
-
}
|
|
533
|
-
|
|
534
|
-
function downstreamForGlobalToolInstall(prototype: any, previous: any): ToolRenderMethods {
|
|
467
|
+
function downstreamForGlobalToolInstall(
|
|
468
|
+
prototype: any,
|
|
469
|
+
previous: GlobalToolRenderPatch | undefined,
|
|
470
|
+
): ToolRenderMethods {
|
|
535
471
|
const current = prototypeToolRenderMethods(prototype);
|
|
536
|
-
if (!previous || previous.prototype !== prototype)
|
|
537
|
-
|
|
538
|
-
return {
|
|
539
|
-
hasRendererDefinition:
|
|
540
|
-
current.hasRendererDefinition === previous.installed.hasRendererDefinition
|
|
541
|
-
? previous.downstream.hasRendererDefinition
|
|
542
|
-
: current.hasRendererDefinition,
|
|
543
|
-
getRenderShell:
|
|
544
|
-
current.getRenderShell === previous.installed.getRenderShell
|
|
545
|
-
? previous.downstream.getRenderShell
|
|
546
|
-
: current.getRenderShell,
|
|
547
|
-
getCallRenderer:
|
|
548
|
-
current.getCallRenderer === previous.installed.getCallRenderer
|
|
549
|
-
? previous.downstream.getCallRenderer
|
|
550
|
-
: current.getCallRenderer,
|
|
551
|
-
getResultRenderer:
|
|
552
|
-
current.getResultRenderer === previous.installed.getResultRenderer
|
|
553
|
-
? previous.downstream.getResultRenderer
|
|
554
|
-
: current.getResultRenderer,
|
|
555
|
-
};
|
|
472
|
+
if (!previous || previous.prototype !== prototype || !isOwnershipAwarePatch(previous)) {
|
|
473
|
+
return current;
|
|
556
474
|
}
|
|
557
|
-
|
|
558
|
-
// pre-v2 Symbol 无 wrapper 引用;能识别则回退,否则保留当前方法为 external。
|
|
559
|
-
const legacyDownstream = (method: Function, field: string): Function => {
|
|
560
|
-
const saved = previous[field];
|
|
561
|
-
return typeof saved === "function" && isLegacyInstalledWrapper(method, field) ? saved : method;
|
|
562
|
-
};
|
|
563
475
|
return {
|
|
564
|
-
hasRendererDefinition:
|
|
565
|
-
current.hasRendererDefinition
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
getRenderShell:
|
|
569
|
-
current.getRenderShell
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
getCallRenderer:
|
|
573
|
-
current.getCallRenderer
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
getResultRenderer:
|
|
577
|
-
current.getResultRenderer
|
|
578
|
-
|
|
579
|
-
|
|
476
|
+
hasRendererDefinition:
|
|
477
|
+
current.hasRendererDefinition === previous.installed.hasRendererDefinition
|
|
478
|
+
? previous.downstream.hasRendererDefinition
|
|
479
|
+
: current.hasRendererDefinition,
|
|
480
|
+
getRenderShell:
|
|
481
|
+
current.getRenderShell === previous.installed.getRenderShell
|
|
482
|
+
? previous.downstream.getRenderShell
|
|
483
|
+
: current.getRenderShell,
|
|
484
|
+
getCallRenderer:
|
|
485
|
+
current.getCallRenderer === previous.installed.getCallRenderer
|
|
486
|
+
? previous.downstream.getCallRenderer
|
|
487
|
+
: current.getCallRenderer,
|
|
488
|
+
getResultRenderer:
|
|
489
|
+
current.getResultRenderer === previous.installed.getResultRenderer
|
|
490
|
+
? previous.downstream.getResultRenderer
|
|
491
|
+
: current.getResultRenderer,
|
|
580
492
|
};
|
|
581
493
|
}
|
|
582
494
|
|
|
583
|
-
function disconnectGlobalToolRenderPatch(patch:
|
|
584
|
-
if (!patch
|
|
495
|
+
function disconnectGlobalToolRenderPatch(patch: GlobalToolRenderPatch | undefined): void {
|
|
496
|
+
if (!patch) return;
|
|
585
497
|
patch.active = false;
|
|
586
|
-
patch.enabled = () => false;
|
|
587
|
-
patch.mode = () => "off";
|
|
588
|
-
patch.wrap = (tool: any) => tool;
|
|
589
498
|
patch.byDefinition = new WeakMap();
|
|
590
|
-
|
|
591
|
-
|
|
499
|
+
patch.byName.clear();
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
function ioHoverOf(tool: any): string | null {
|
|
503
|
+
const view = tool?.resultRendererComponent;
|
|
504
|
+
if (!view || typeof view.getHoveredSection !== "function") return null;
|
|
505
|
+
return view.getHoveredSection();
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
function toolPaintMatches(hit: ToolPaintHit, tool: any, width: number): boolean {
|
|
509
|
+
return (
|
|
510
|
+
hit.width === width &&
|
|
511
|
+
hit.expanded === Boolean(tool.expanded) &&
|
|
512
|
+
hit.isPartial === Boolean(tool.isPartial) &&
|
|
513
|
+
hit.result === tool.result &&
|
|
514
|
+
hit.args === tool.args &&
|
|
515
|
+
hit.callHover === isToolCallHovered(tool.toolCallId) &&
|
|
516
|
+
hit.ioHover === ioHoverOf(tool)
|
|
517
|
+
);
|
|
592
518
|
}
|
|
593
519
|
|
|
594
520
|
function installGlobalToolRendering(
|
|
595
521
|
writeExecutionMetadata: WriteExecutionMetadataStore,
|
|
596
522
|
): GlobalToolRenderPatch {
|
|
597
523
|
const prototype = (ToolExecutionComponent as any).prototype;
|
|
598
|
-
const
|
|
599
|
-
const previous = host[GLOBAL_TOOL_RENDER_PATCH];
|
|
524
|
+
const previous = patchRegistry.get<GlobalToolRenderPatch>(GLOBAL_TOOL_RENDER_PATCH);
|
|
600
525
|
const downstream = downstreamForGlobalToolInstall(prototype, previous);
|
|
601
|
-
|
|
602
|
-
|
|
526
|
+
const originalRender =
|
|
527
|
+
previous?.originalRender && prototype.render === previous.renderPaint
|
|
528
|
+
? previous.originalRender
|
|
529
|
+
: prototype.render;
|
|
530
|
+
const originalInvalidate =
|
|
531
|
+
previous?.originalInvalidate && prototype.invalidate === previous.invalidatePaint
|
|
532
|
+
? previous.originalInvalidate
|
|
533
|
+
: prototype.invalidate;
|
|
534
|
+
if (isOwnershipAwarePatch(previous)) disconnectGlobalToolRenderPatch(previous);
|
|
603
535
|
|
|
604
536
|
const patch: GlobalToolRenderPatch = {
|
|
605
537
|
version: 2,
|
|
606
538
|
prototype,
|
|
607
|
-
owner: {},
|
|
608
539
|
active: true,
|
|
609
|
-
enabled: () => config.mode === "on",
|
|
610
540
|
mode: () => config.mode,
|
|
611
541
|
wrap: (tool: any) => createCcstyleTool(tool, writeExecutionMetadata),
|
|
612
542
|
byDefinition: new WeakMap(),
|
|
613
543
|
byName: new Map(),
|
|
614
544
|
downstream,
|
|
615
545
|
installed: undefined as any,
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
originalGetResultRenderer: downstream.getResultRenderer,
|
|
546
|
+
originalRender,
|
|
547
|
+
originalInvalidate,
|
|
548
|
+
paintCache: new WeakMap(),
|
|
620
549
|
};
|
|
621
550
|
|
|
622
551
|
patch.installed = {
|
|
@@ -626,14 +555,12 @@ function installGlobalToolRendering(
|
|
|
626
555
|
},
|
|
627
556
|
getRenderShell: function (this: any, ...args: any[]) {
|
|
628
557
|
if (!patch.active) return patch.downstream.getRenderShell.apply(this, args);
|
|
629
|
-
const useSelfShell = shouldUseSelfShell(this, patch);
|
|
630
558
|
const useCcstyle = shouldGloballyStyleTool(this, patch);
|
|
631
|
-
const shell =
|
|
632
|
-
|
|
633
|
-
? "
|
|
634
|
-
:
|
|
635
|
-
|
|
636
|
-
: patch.downstream.getRenderShell.apply(this, args);
|
|
559
|
+
const shell = useCcstyle
|
|
560
|
+
? this.expanded
|
|
561
|
+
? "default"
|
|
562
|
+
: "self"
|
|
563
|
+
: patch.downstream.getRenderShell.apply(this, args);
|
|
637
564
|
syncToolShell(this, shell);
|
|
638
565
|
return shell;
|
|
639
566
|
},
|
|
@@ -655,7 +582,42 @@ function installGlobalToolRendering(
|
|
|
655
582
|
prototype.getRenderShell = patch.installed.getRenderShell;
|
|
656
583
|
prototype.getCallRenderer = patch.installed.getCallRenderer;
|
|
657
584
|
prototype.getResultRenderer = patch.installed.getResultRenderer;
|
|
658
|
-
|
|
585
|
+
// fullscreen 滚动/选区每帧整树 render;内容未变时复用上一帧行,避免重做 diff/Box。
|
|
586
|
+
patch.renderPaint = function (this: any, width: number): string[] {
|
|
587
|
+
if (!patch.active || patch.mode() === "off") {
|
|
588
|
+
return originalRender.call(this, width);
|
|
589
|
+
}
|
|
590
|
+
const cache = patch.paintCache;
|
|
591
|
+
// A running partial tool owns a time-varying spinner. Light animation ticks
|
|
592
|
+
// request a repaint without invalidating the component, so settled-content
|
|
593
|
+
// caching must not intercept those paints.
|
|
594
|
+
const cacheable = !(this.executionStarted && this.isPartial);
|
|
595
|
+
const hit = cacheable ? cache?.get(this) : undefined;
|
|
596
|
+
if (hit && toolPaintMatches(hit, this, width)) return hit.lines;
|
|
597
|
+
const lines = originalRender.call(this, width);
|
|
598
|
+
if (cacheable) {
|
|
599
|
+
cache?.set(this, {
|
|
600
|
+
width,
|
|
601
|
+
expanded: Boolean(this.expanded),
|
|
602
|
+
isPartial: Boolean(this.isPartial),
|
|
603
|
+
result: this.result,
|
|
604
|
+
args: this.args,
|
|
605
|
+
callHover: isToolCallHovered(this.toolCallId),
|
|
606
|
+
ioHover: ioHoverOf(this),
|
|
607
|
+
lines,
|
|
608
|
+
});
|
|
609
|
+
} else {
|
|
610
|
+
cache?.delete(this);
|
|
611
|
+
}
|
|
612
|
+
return lines;
|
|
613
|
+
};
|
|
614
|
+
patch.invalidatePaint = function (this: any): void {
|
|
615
|
+
patch.paintCache?.delete(this);
|
|
616
|
+
originalInvalidate.call(this);
|
|
617
|
+
};
|
|
618
|
+
prototype.render = patch.renderPaint;
|
|
619
|
+
prototype.invalidate = patch.invalidatePaint;
|
|
620
|
+
patchRegistry.install(GLOBAL_TOOL_RENDER_PATCH, patch);
|
|
659
621
|
return patch;
|
|
660
622
|
}
|
|
661
623
|
|
|
@@ -675,15 +637,23 @@ function deactivateGlobalToolRendering(patch: GlobalToolRenderPatch): void {
|
|
|
675
637
|
if (prototype.getResultRenderer === patch.installed.getResultRenderer) {
|
|
676
638
|
prototype.getResultRenderer = patch.downstream.getResultRenderer;
|
|
677
639
|
}
|
|
640
|
+
if (patch.renderPaint && prototype.render === patch.renderPaint && patch.originalRender) {
|
|
641
|
+
prototype.render = patch.originalRender;
|
|
642
|
+
}
|
|
643
|
+
if (
|
|
644
|
+
patch.invalidatePaint &&
|
|
645
|
+
prototype.invalidate === patch.invalidatePaint &&
|
|
646
|
+
patch.originalInvalidate
|
|
647
|
+
) {
|
|
648
|
+
prototype.invalidate = patch.originalInvalidate;
|
|
649
|
+
}
|
|
678
650
|
}
|
|
679
651
|
|
|
680
652
|
/** 展开面板背景统一为 user message 背景色;折叠行保持原生状态色。
|
|
681
653
|
* 必须在 compact-mode 之后安装,shutdown 时先于 compact-mode 释放。 */
|
|
682
654
|
export function installToolExpandedBackground(): () => void {
|
|
683
|
-
const
|
|
684
|
-
const previous = host[TOOL_EXPANDED_BACKGROUND_PATCH] as ToolExpandedBackgroundPatch | undefined;
|
|
655
|
+
const previous = patchRegistry.get<ToolExpandedBackgroundPatch>(TOOL_EXPANDED_BACKGROUND_PATCH);
|
|
685
656
|
if (previous) previous.dispose();
|
|
686
|
-
// SAFETY: Pi's runtime ToolExecutionComponent prototype owns updateDisplay; its public type omits it.
|
|
687
657
|
const prototype = ToolExecutionComponent.prototype as unknown as { updateDisplay: () => void };
|
|
688
658
|
const original = prototype.updateDisplay;
|
|
689
659
|
const patch: ToolExpandedBackgroundPatch = {
|
|
@@ -695,7 +665,12 @@ export function installToolExpandedBackground(): () => void {
|
|
|
695
665
|
const theme = getMessageDisplayTheme();
|
|
696
666
|
if (!theme?.bg) return;
|
|
697
667
|
const box = this.contentBox;
|
|
698
|
-
|
|
668
|
+
// 展开最外层卡片:上下左右内间距 1 格
|
|
669
|
+
if (box) {
|
|
670
|
+
box.paddingX = 1;
|
|
671
|
+
box.paddingY = 1;
|
|
672
|
+
if (box.setBgFn) box.setBgFn((text: string) => theme.bg("userMessageBg", text));
|
|
673
|
+
}
|
|
699
674
|
},
|
|
700
675
|
original,
|
|
701
676
|
dispose: () => {
|
|
@@ -703,13 +678,11 @@ export function installToolExpandedBackground(): () => void {
|
|
|
703
678
|
if (prototype.updateDisplay === patch.installed) {
|
|
704
679
|
prototype.updateDisplay = original;
|
|
705
680
|
}
|
|
706
|
-
|
|
707
|
-
delete host[TOOL_EXPANDED_BACKGROUND_PATCH];
|
|
708
|
-
}
|
|
681
|
+
patchRegistry.dispose(TOOL_EXPANDED_BACKGROUND_PATCH, patch);
|
|
709
682
|
},
|
|
710
683
|
};
|
|
711
684
|
prototype.updateDisplay = patch.installed;
|
|
712
|
-
|
|
685
|
+
patchRegistry.install(TOOL_EXPANDED_BACKGROUND_PATCH, patch);
|
|
713
686
|
return patch.dispose;
|
|
714
687
|
}
|
|
715
688
|
|
|
@@ -721,7 +694,7 @@ export function installDefaultMode(
|
|
|
721
694
|
return {
|
|
722
695
|
isOwner() {
|
|
723
696
|
return (
|
|
724
|
-
(
|
|
697
|
+
patchRegistry.owns(GLOBAL_TOOL_RENDER_PATCH, globalToolRendering) &&
|
|
725
698
|
globalToolRendering.active
|
|
726
699
|
);
|
|
727
700
|
},
|