@herbertgao/pi-extensions 2026.9.18 → 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 +20 -28
- package/THIRD_PARTY_NOTICES.md +1 -1
- 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 +75 -40
- 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 +42 -41
- 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 +47 -10
- 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 +145 -190
- 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 +8 -8
- package/node_modules/pi-antigravity/README.md +29 -6
- package/node_modules/pi-antigravity/package.json +12 -7
- package/node_modules/pi-antigravity/src/auth/accounts.ts +327 -0
- package/node_modules/pi-antigravity/src/auth/index.ts +9 -0
- package/node_modules/pi-antigravity/src/client/client.ts +1 -1
- package/node_modules/pi-antigravity/src/image/image.ts +4 -4
- package/node_modules/pi-antigravity/src/index.ts +203 -13
- package/node_modules/pi-antigravity/src/search/index.ts +1 -0
- package/node_modules/pi-antigravity/src/search/search.ts +325 -0
- package/node_modules/pi-antigravity/src/stream/stream.ts +191 -14
- package/node_modules/pi-antigravity/src/types/enums.ts +45 -36
- package/node_modules/pi-antigravity/src/types/types.ts +5 -12
- package/node_modules/pi-antigravity/src/utils/http.ts +7 -2
- package/node_modules/pi-antigravity/src/utils/util.ts +31 -3
- package/node_modules/pi-typesafe/README.md +2 -0
- package/node_modules/pi-typesafe/package.json +2 -1
- package/node_modules/pi-web-access/CHANGELOG.md +72 -0
- package/node_modules/pi-web-access/README.md +34 -13
- package/node_modules/pi-web-access/chrome-cookies.ts +79 -25
- package/node_modules/pi-web-access/curator-page.ts +5 -1
- package/node_modules/pi-web-access/curator-server.ts +2 -0
- package/node_modules/pi-web-access/dist/index.js +1337 -1009
- package/node_modules/pi-web-access/exa.ts +20 -52
- package/node_modules/pi-web-access/extract.ts +41 -4
- package/node_modules/pi-web-access/gemini-search.ts +12 -4
- package/node_modules/pi-web-access/index.ts +29 -37
- package/node_modules/pi-web-access/openai-search.ts +35 -7
- package/node_modules/pi-web-access/package.json +6 -5
- package/node_modules/pi-web-access/page-query.ts +2 -2
- package/node_modules/pi-web-access/query-rewrite.ts +2 -3
- package/node_modules/pi-web-access/ssrf-protection.ts +27 -10
- package/node_modules/pi-web-access/storage.ts +48 -77
- package/node_modules/pi-web-access/summary-model-scope.ts +6 -77
- package/node_modules/pi-web-access/summary-review.ts +3 -4
- package/node_modules/pi-web-access/tavily.ts +67 -20
- package/node_modules/pi-web-access/tool-activation.ts +53 -33
- package/node_modules/pi-web-access/utils.ts +1 -1
- package/node_modules/pi-web-access/you.ts +164 -0
- package/node_modules/pi-web-access/zai.ts +161 -0
- package/package.json +7 -11
- 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
package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/line-width-safety.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { normalizeDiffRenderWidth } from "./diff-presentation.ts";
|
|
2
|
-
import { pluralize } from "./
|
|
3
|
-
import { showMoreHintText } from "
|
|
2
|
+
import { pluralize } from "./diff-text.ts";
|
|
3
|
+
import { showMoreHintText } from "../show-more-hint.ts";
|
|
4
4
|
|
|
5
5
|
export interface WidthMeasurementOps {
|
|
6
6
|
measure(text: string): number;
|
package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/write-execution.ts
CHANGED
|
@@ -94,6 +94,7 @@ export async function executeWriteWithMetadata(
|
|
|
94
94
|
await mkdir(dirname(absolutePath), { recursive: true });
|
|
95
95
|
throwIfAborted();
|
|
96
96
|
await writeFile(absolutePath, params.content, "utf8");
|
|
97
|
+
// 写入后不再检查 abort:文件已变更,必须如实报告成功
|
|
97
98
|
store.set(toolCallId, metadata);
|
|
98
99
|
return {
|
|
99
100
|
content: [
|
|
@@ -7,13 +7,26 @@ import {
|
|
|
7
7
|
type Component,
|
|
8
8
|
} from "@earendil-works/pi-tui";
|
|
9
9
|
import { TOOL_LOADING_INTERVAL_MS, toolLoadingIcon } from "../../utils/tool-loading-icon.ts";
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import { isToolTuiFullscreen, showMoreHintText } from "
|
|
10
|
+
import { getToolMouseTui } from "../mouse/scroll.ts";
|
|
11
|
+
import { mcpToolTitle } from "./mcp-title.ts";
|
|
12
|
+
import { collapseHintText, isToolTuiFullscreen, showMoreHintText } from "./show-more-hint.ts";
|
|
13
|
+
import { stripAnsi, stripBackgroundAnsi, stripLeadingStatusIcon } from "../../utils/ansi-text.ts";
|
|
14
|
+
import { walkComponentTree } from "../../utils/component-tree.ts";
|
|
15
|
+
import {
|
|
16
|
+
fitToolCallSummary,
|
|
17
|
+
humanizeToolLabel,
|
|
18
|
+
renderToolSummary,
|
|
19
|
+
toolCallSummary,
|
|
20
|
+
type ToolCallSummary,
|
|
21
|
+
} from "./names.ts";
|
|
22
|
+
import { toolViewportWidth } from "./result.ts";
|
|
23
|
+
import {
|
|
24
|
+
patchRegistry,
|
|
25
|
+
TOOL_GROUPING_GENERATION_KEY as GENERATION_KEY,
|
|
26
|
+
TOOL_GROUPING_PARENT_KEY as PARENT_KEY,
|
|
27
|
+
TOOL_GROUPING_PATCH_KEY as PATCH_KEY,
|
|
28
|
+
} from "../../utils/patch-keys.ts";
|
|
13
29
|
|
|
14
|
-
const PATCH_KEY = Symbol.for("pi.ccstyle.tool-grouping-patch");
|
|
15
|
-
const PARENT_KEY = Symbol.for("pi.ccstyle.tool-grouping-parent");
|
|
16
|
-
const GENERATION_KEY = Symbol.for("pi.ccstyle.tool-grouping-generation");
|
|
17
30
|
const NON_GROUPABLE = new Set(["edit", "write", "apply_patch"]);
|
|
18
31
|
|
|
19
32
|
type Patch = {
|
|
@@ -34,7 +47,20 @@ function toolName(tool: any): string {
|
|
|
34
47
|
return String(tool?.toolName ?? tool?.toolDefinition?.name ?? "tool");
|
|
35
48
|
}
|
|
36
49
|
|
|
37
|
-
|
|
50
|
+
/**
|
|
51
|
+
* 标题:MCP 工具用 adapter 暴露的真实工具名,其余回退工具名人性化。
|
|
52
|
+
*/
|
|
53
|
+
function toolTitle(tool: any): string {
|
|
54
|
+
const name = toolName(tool);
|
|
55
|
+
return (
|
|
56
|
+
mcpToolTitle({
|
|
57
|
+
toolName: name,
|
|
58
|
+
definition: tool?.toolDefinition ?? tool?.builtInToolDefinition,
|
|
59
|
+
}) ?? humanizeToolLabel(name)
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function isGroupable(value: unknown): boolean {
|
|
38
64
|
return value instanceof ToolExecutionComponent && !NON_GROUPABLE.has(toolName(value));
|
|
39
65
|
}
|
|
40
66
|
|
|
@@ -80,37 +106,42 @@ function scheduleGroupAnimation(patch: Patch): void {
|
|
|
80
106
|
patch.animationTimer = setTimeout(() => {
|
|
81
107
|
patch.animationTimer = null;
|
|
82
108
|
if (!patch.active) return;
|
|
109
|
+
let needsRender = false;
|
|
83
110
|
for (const group of patch.groups) {
|
|
84
111
|
if (
|
|
85
112
|
(group.children as any[]).some(
|
|
86
113
|
(tool) => tool?.executionStarted && status(tool) === "pending",
|
|
87
114
|
)
|
|
88
|
-
)
|
|
115
|
+
) {
|
|
89
116
|
group.invalidate();
|
|
117
|
+
// 分组卡不是 ToolExecutionComponent:它的 invalidate() 不会请求渲染,
|
|
118
|
+
// 不补这一步 spinner 只在别人渲染时才跳帧(并行工具下表现为卡顿/冻结)。
|
|
119
|
+
needsRender = true;
|
|
120
|
+
}
|
|
90
121
|
}
|
|
122
|
+
if (needsRender) requestAnimationRender(patch);
|
|
91
123
|
}, TOOL_LOADING_INTERVAL_MS);
|
|
92
124
|
patch.animationTimer.unref?.();
|
|
93
125
|
}
|
|
94
126
|
|
|
95
|
-
|
|
96
|
-
|
|
127
|
+
/** 借用子工具卡的 ui 请求一帧;子卡缺失时回退到扩展持有的 TUI 槽。 */
|
|
128
|
+
function requestAnimationRender(patch: Patch): void {
|
|
129
|
+
for (const group of patch.groups) {
|
|
130
|
+
const ui = (group.children as any[]).find(
|
|
131
|
+
(tool) => typeof tool?.ui?.requestRender === "function",
|
|
132
|
+
)?.ui;
|
|
133
|
+
if (ui) {
|
|
134
|
+
ui.requestRender();
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
getToolMouseTui()?.requestRender?.();
|
|
97
139
|
}
|
|
98
140
|
|
|
99
141
|
function visibleLines(lines: string[]): string[] {
|
|
100
142
|
return lines.filter((line) => stripAnsi(line).trim());
|
|
101
143
|
}
|
|
102
144
|
|
|
103
|
-
function stripLeadingStatusIcon(line: string): string {
|
|
104
|
-
return line.replace(
|
|
105
|
-
/^((?:\x1b\[[0-9;]*m|[ \t]|[├└│─])*)(?:\x1b\[[0-9;]*m)*(?:[✓✗●○■⬤•·⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏])(?:\x1b\[[0-9;]*m)*\s+/,
|
|
106
|
-
"$1",
|
|
107
|
-
);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
export function stripBackgroundAnsi(line: string): string {
|
|
111
|
-
return line.replace(/\x1b\[(?:4[0-9]|10[0-7]|48(?:(?:;|:)[0-9]+)+|49)m/g, "");
|
|
112
|
-
}
|
|
113
|
-
|
|
114
145
|
function stripLeadingSpaces(line: string, count: number): string {
|
|
115
146
|
let offset = 0;
|
|
116
147
|
let removed = 0;
|
|
@@ -133,10 +164,6 @@ function stripLeadingSpaces(line: string, count: number): string {
|
|
|
133
164
|
}
|
|
134
165
|
|
|
135
166
|
/** 生成一行铺满 width 的 slot 背景行;bgAnsiOverride 可替换背景 ANSI(用于提亮等)。 */
|
|
136
|
-
function panelInnerWidth(width: number): number {
|
|
137
|
-
return Math.max(0, Math.floor(width) - 2);
|
|
138
|
-
}
|
|
139
|
-
|
|
140
167
|
export function paddedBackgroundRow(
|
|
141
168
|
theme: any,
|
|
142
169
|
slot: string,
|
|
@@ -144,12 +171,9 @@ export function paddedBackgroundRow(
|
|
|
144
171
|
width: number,
|
|
145
172
|
bgAnsiOverride?: string,
|
|
146
173
|
): string {
|
|
147
|
-
const
|
|
148
|
-
const leftPadding = safeWidth > 0 ? " " : "";
|
|
149
|
-
const rightPadding = safeWidth > 1 ? " " : "";
|
|
150
|
-
const innerWidth = panelInnerWidth(width);
|
|
174
|
+
const innerWidth = Math.max(0, width - 2);
|
|
151
175
|
const clipped = truncateToWidth(stripBackgroundAnsi(content), innerWidth, "");
|
|
152
|
-
const row =
|
|
176
|
+
const row = ` ${clipped}${" ".repeat(Math.max(0, innerWidth - visibleWidth(clipped)))} `;
|
|
153
177
|
const bgAnsi =
|
|
154
178
|
bgAnsiOverride ||
|
|
155
179
|
(typeof theme?.bg === "function"
|
|
@@ -160,113 +184,12 @@ export function paddedBackgroundRow(
|
|
|
160
184
|
return `${bgAnsi}${stable}\x1b[49m`;
|
|
161
185
|
}
|
|
162
186
|
|
|
163
|
-
function oneLine(value: unknown): string {
|
|
164
|
-
return sanitizeToolResultText(String(value ?? ""), 4096)
|
|
165
|
-
.replace(/\s+/g, " ")
|
|
166
|
-
.trim();
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
function humanizeToolName(name: string): string {
|
|
170
|
-
return name
|
|
171
|
-
.replace(/([a-z0-9])([A-Z])/g, "$1 $2")
|
|
172
|
-
.replace(/[_-]+/g, " ")
|
|
173
|
-
.replace(/\b\w/g, (char) => char.toUpperCase());
|
|
174
|
-
}
|
|
175
|
-
|
|
176
187
|
function toolSummary(tool: any): ToolCallSummary {
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
const found = keys.map((key) => args[key]).find((item) => typeof item === "string" && item);
|
|
183
|
-
return `${titled} ${oneLine(found || fallback)}`;
|
|
184
|
-
};
|
|
185
|
-
if (lowerName === "agent" || lowerName === "agents") {
|
|
186
|
-
const displayName = args.subagent_type ?? args.agent_type ?? args.agent;
|
|
187
|
-
if (typeof displayName === "string" && displayName) {
|
|
188
|
-
return { main: `${titled} ${displayName}`, detail: "" };
|
|
189
|
-
}
|
|
190
|
-
return {
|
|
191
|
-
main: value(
|
|
192
|
-
lowerName === "agent" ? "launch agent" : "launch agents",
|
|
193
|
-
"description",
|
|
194
|
-
"prompt",
|
|
195
|
-
),
|
|
196
|
-
detail: "",
|
|
197
|
-
};
|
|
198
|
-
}
|
|
199
|
-
if (lowerName === "get_subagent_result" || lowerName === "steer_subagent") {
|
|
200
|
-
return {
|
|
201
|
-
main: value(lowerName === "get_subagent_result" ? "agent result" : "steer agent", "agent_id"),
|
|
202
|
-
detail: "",
|
|
203
|
-
};
|
|
204
|
-
}
|
|
205
|
-
if (lowerName === "skill") return { main: value("run skill", "name"), detail: "" };
|
|
206
|
-
if (lowerName === "enterplanmode" || lowerName === "enter_plan_mode") {
|
|
207
|
-
return { main: `${titled} enable read-only planning`, detail: "" };
|
|
208
|
-
}
|
|
209
|
-
if (lowerName === "exitplanmode" || lowerName === "exit_plan_mode") {
|
|
210
|
-
return { main: `${titled} present plan`, detail: "" };
|
|
211
|
-
}
|
|
212
|
-
if (lowerName === "taskcreate") return { main: value("create task", "subject"), detail: "" };
|
|
213
|
-
if (lowerName === "tasklist") return { main: `${titled} task list`, detail: "" };
|
|
214
|
-
if (lowerName === "taskget" || lowerName === "taskupdate") {
|
|
215
|
-
return { main: value("task", "taskId", "task_id"), detail: "" };
|
|
216
|
-
}
|
|
217
|
-
if (lowerName === "taskoutput" || lowerName === "taskstop") {
|
|
218
|
-
return { main: value("background task", "task_id", "taskId"), detail: "" };
|
|
219
|
-
}
|
|
220
|
-
if (lowerName === "taskexecute") {
|
|
221
|
-
const ids = Array.isArray(args.task_ids)
|
|
222
|
-
? args.task_ids
|
|
223
|
-
: Array.isArray(args.taskIds)
|
|
224
|
-
? args.taskIds
|
|
225
|
-
: [];
|
|
226
|
-
return {
|
|
227
|
-
main: `${titled} ${ids.length ? `${ids[0]}${ids.length > 1 ? ` (+${ids.length - 1} tasks)` : ""}` : "start tasks"}`,
|
|
228
|
-
detail: "",
|
|
229
|
-
};
|
|
230
|
-
}
|
|
231
|
-
if (name === "read") {
|
|
232
|
-
const details = [
|
|
233
|
-
args.offset !== undefined ? `offset=${args.offset}` : "",
|
|
234
|
-
args.limit !== undefined ? `limit=${args.limit}` : "",
|
|
235
|
-
].filter(Boolean);
|
|
236
|
-
const detail = details.length ? ` (${details.join(", ")})` : "";
|
|
237
|
-
if (typeof args.path === "string" && args.path) {
|
|
238
|
-
return pathSummary("Read", args.path, tool?.cwd, detail);
|
|
239
|
-
}
|
|
240
|
-
return { main: "Read ...", detail };
|
|
241
|
-
}
|
|
242
|
-
if (name === "bash") return { main: `Bash ${oneLine(args.command || "...")}`, detail: "" };
|
|
243
|
-
if (name === "grep") {
|
|
244
|
-
const pattern = oneLine(args.pattern || "...");
|
|
245
|
-
return {
|
|
246
|
-
main: `Grep ${JSON.stringify(pattern)}${args.path ? ` in ${oneLine(args.path)}` : ""}`,
|
|
247
|
-
detail: "",
|
|
248
|
-
};
|
|
249
|
-
}
|
|
250
|
-
if (name === "find") {
|
|
251
|
-
const pattern = oneLine(args.pattern || "...");
|
|
252
|
-
return {
|
|
253
|
-
main: `Find ${JSON.stringify(pattern)}${args.path ? ` in ${oneLine(args.path)}` : ""}`,
|
|
254
|
-
detail: "",
|
|
255
|
-
};
|
|
256
|
-
}
|
|
257
|
-
const preferred =
|
|
258
|
-
args.agent_id ??
|
|
259
|
-
args.path ??
|
|
260
|
-
args.file_path ??
|
|
261
|
-
args.url ??
|
|
262
|
-
args.description ??
|
|
263
|
-
args.query ??
|
|
264
|
-
args.name ??
|
|
265
|
-
args.prompt;
|
|
266
|
-
return {
|
|
267
|
-
main: `${humanizeToolName(name)}${preferred === undefined ? "" : ` ${oneLine(preferred)}`}`,
|
|
268
|
-
detail: "",
|
|
269
|
-
};
|
|
188
|
+
return toolCallSummary(toolName(tool), tool?.args ?? {}, {
|
|
189
|
+
title: toolTitle(tool),
|
|
190
|
+
variant: "grouping",
|
|
191
|
+
cwd: tool?.cwd,
|
|
192
|
+
});
|
|
270
193
|
}
|
|
271
194
|
|
|
272
195
|
function toolNameList(tools: any[]): string {
|
|
@@ -277,10 +200,6 @@ function toolNameList(tools: any[]): string {
|
|
|
277
200
|
|
|
278
201
|
let nextGroupId = 1;
|
|
279
202
|
|
|
280
|
-
function groupChildWidth(width: number): number {
|
|
281
|
-
return Math.max(1, panelInnerWidth(width));
|
|
282
|
-
}
|
|
283
|
-
|
|
284
203
|
type SettledGroupCache = {
|
|
285
204
|
width: number;
|
|
286
205
|
hover: boolean;
|
|
@@ -292,6 +211,15 @@ type SettledGroupCache = {
|
|
|
292
211
|
lines: string[];
|
|
293
212
|
};
|
|
294
213
|
|
|
214
|
+
type ExpandedGroupCache = {
|
|
215
|
+
width: number;
|
|
216
|
+
hover: boolean;
|
|
217
|
+
theme: unknown;
|
|
218
|
+
fullscreen: boolean;
|
|
219
|
+
paints: readonly unknown[];
|
|
220
|
+
lines: string[];
|
|
221
|
+
};
|
|
222
|
+
|
|
295
223
|
export class ToolGroupComponent extends Container {
|
|
296
224
|
readonly toolCallId = `ccstyle-tool-group-${nextGroupId++}`;
|
|
297
225
|
readonly toolName = "Tool group";
|
|
@@ -302,8 +230,10 @@ export class ToolGroupComponent extends Container {
|
|
|
302
230
|
}
|
|
303
231
|
private hintHovered = false;
|
|
304
232
|
private readonly patch: Patch;
|
|
305
|
-
/** 仅缓存已完成且折叠的分组;pending
|
|
233
|
+
/** 仅缓存已完成且折叠的分组;pending 每帧现算。 */
|
|
306
234
|
private settledCache: SettledGroupCache | undefined;
|
|
235
|
+
/** 展开分组:子工具 paint 引用未变则复用整卡行。 */
|
|
236
|
+
private expandedPaintCache: ExpandedGroupCache | undefined;
|
|
307
237
|
|
|
308
238
|
constructor(patch: Patch) {
|
|
309
239
|
super();
|
|
@@ -311,14 +241,19 @@ export class ToolGroupComponent extends Container {
|
|
|
311
241
|
patch.groups.add(this);
|
|
312
242
|
}
|
|
313
243
|
|
|
314
|
-
|
|
244
|
+
private clearPaintCache(): void {
|
|
315
245
|
this.settledCache = undefined;
|
|
246
|
+
this.expandedPaintCache = undefined;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
addTool(tool: any): void {
|
|
250
|
+
this.clearPaintCache();
|
|
316
251
|
this.children.push(tool);
|
|
317
252
|
tool[PARENT_KEY] = this;
|
|
318
253
|
}
|
|
319
254
|
|
|
320
255
|
releaseTools(): any[] {
|
|
321
|
-
this.
|
|
256
|
+
this.clearPaintCache();
|
|
322
257
|
const tools = [...this.children];
|
|
323
258
|
this.children.length = 0;
|
|
324
259
|
this.patch.groups.delete(this);
|
|
@@ -326,27 +261,27 @@ export class ToolGroupComponent extends Container {
|
|
|
326
261
|
}
|
|
327
262
|
|
|
328
263
|
removeTool(tool: any): void {
|
|
329
|
-
this.
|
|
264
|
+
this.clearPaintCache();
|
|
330
265
|
const index = this.children.indexOf(tool);
|
|
331
266
|
if (index >= 0) this.children.splice(index, 1);
|
|
332
267
|
if (tool?.[PARENT_KEY] === this) delete tool[PARENT_KEY];
|
|
333
268
|
}
|
|
334
269
|
|
|
335
270
|
setExpanded(expanded: boolean): void {
|
|
336
|
-
if (this._expanded !== expanded) this.
|
|
271
|
+
if (this._expanded !== expanded) this.clearPaintCache();
|
|
337
272
|
this._expanded = expanded;
|
|
338
273
|
for (const tool of this.children)
|
|
339
274
|
(tool as Component & { setExpanded?: (expanded: boolean) => void }).setExpanded?.(expanded);
|
|
340
275
|
}
|
|
341
276
|
|
|
342
277
|
setHintHovered(hovered: boolean): void {
|
|
343
|
-
if (this.hintHovered !== hovered) this.
|
|
278
|
+
if (this.hintHovered !== hovered) this.clearPaintCache();
|
|
344
279
|
this.hintHovered = hovered;
|
|
345
280
|
}
|
|
346
281
|
|
|
347
282
|
/**
|
|
348
283
|
* 展开时按局部行定位内部组件(null = 行属于 group 自身:空行/头行/尾行)。
|
|
349
|
-
* 行数计算与 render
|
|
284
|
+
* 行数计算与 render 保持一致:宽度 width-2 + 空行过滤。
|
|
350
285
|
*/
|
|
351
286
|
childAtRow(localRow: number, width: number): { component: any; row: number } | null {
|
|
352
287
|
if (!this._expanded || localRow < 2) return null;
|
|
@@ -354,7 +289,7 @@ export class ToolGroupComponent extends Container {
|
|
|
354
289
|
for (const tool of this.children) {
|
|
355
290
|
let lines: string[] = [];
|
|
356
291
|
try {
|
|
357
|
-
const rendered = tool.render?.(
|
|
292
|
+
const rendered = tool.render?.(Math.max(1, width - 2));
|
|
358
293
|
if (Array.isArray(rendered)) lines = visibleLines(rendered.map((line) => String(line)));
|
|
359
294
|
} catch {
|
|
360
295
|
lines = [];
|
|
@@ -369,7 +304,7 @@ export class ToolGroupComponent extends Container {
|
|
|
369
304
|
}
|
|
370
305
|
|
|
371
306
|
invalidate(): void {
|
|
372
|
-
this.
|
|
307
|
+
this.clearPaintCache();
|
|
373
308
|
for (const tool of this.children) tool.invalidate?.();
|
|
374
309
|
}
|
|
375
310
|
|
|
@@ -429,8 +364,7 @@ export class ToolGroupComponent extends Container {
|
|
|
429
364
|
})
|
|
430
365
|
.join(` ${fg("dim", "•")} `);
|
|
431
366
|
const names = new Set(this.children.map(toolName));
|
|
432
|
-
const label =
|
|
433
|
-
names.size === 1 ? humanizeToolName(toolName(this.children[0])) : "Multiple Tools";
|
|
367
|
+
const label = names.size === 1 ? toolTitle(this.children[0]) : "Multiple Tools";
|
|
434
368
|
const overall: ToolStatus = counts.error ? "error" : counts.pending ? "pending" : "success";
|
|
435
369
|
if (
|
|
436
370
|
(this.children as any[]).some((tool) => tool?.executionStarted && status(tool) === "pending")
|
|
@@ -439,16 +373,42 @@ export class ToolGroupComponent extends Container {
|
|
|
439
373
|
const overallColor = overall === "pending" ? "accent" : overall;
|
|
440
374
|
const nameList = names.size > 1 ? ` ${fg("dim", `• ${toolNameList(this.children)}`)}` : "";
|
|
441
375
|
// 圆点保持 dim;hover 只高亮可点击文字。
|
|
442
|
-
const
|
|
443
|
-
const
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
376
|
+
const hintText = this._expanded ? collapseHintText() : showMoreHintText();
|
|
377
|
+
const hint = `${fg("dim", "•")} ${fg(this.hintHovered ? "text" : "dim", hintText)}`;
|
|
378
|
+
// 行尾提示承载折叠分组的可点击区(collapsedHintHitbox 依赖行尾短语)。
|
|
379
|
+
// 空间不足时先省略工具名列表,再截断计数尾部,提示最后让位;
|
|
380
|
+
// 极窄视口连“圆点+标题+计数”都放不下时才回退整行截断。
|
|
381
|
+
const viewport = toolViewportWidth(width);
|
|
382
|
+
const head = ` ${fg(overallColor, "●")} ${label}: ${countText}`;
|
|
383
|
+
const hintWidth = visibleWidth(` ${hint}`);
|
|
384
|
+
const nameBudget = viewport - visibleWidth(head) - hintWidth;
|
|
385
|
+
const elidedName =
|
|
386
|
+
nameList && nameBudget < visibleWidth(nameList)
|
|
387
|
+
? nameBudget >= 4
|
|
388
|
+
? ` ${fg("dim", "…")}`
|
|
389
|
+
: ""
|
|
390
|
+
: nameList;
|
|
391
|
+
const headBudget = viewport - hintWidth - visibleWidth(elidedName);
|
|
392
|
+
const titleLine = `${visibleWidth(head) <= headBudget ? head : truncateToWidth(head, headBudget, "…")}${elidedName} ${hint}`;
|
|
393
|
+
const lines = ["", truncateToWidth(titleLine, viewport, "…")];
|
|
451
394
|
const total = this.children.length;
|
|
395
|
+
const childPaints = this._expanded
|
|
396
|
+
? (this.children as any[]).map((tool) => tool.render?.(Math.max(1, width - 2)))
|
|
397
|
+
: undefined;
|
|
398
|
+
if (this._expanded && childPaints) {
|
|
399
|
+
const expandedHit = this.expandedPaintCache;
|
|
400
|
+
if (
|
|
401
|
+
expandedHit &&
|
|
402
|
+
expandedHit.width === width &&
|
|
403
|
+
expandedHit.hover === this.hintHovered &&
|
|
404
|
+
expandedHit.theme === this.patch.theme &&
|
|
405
|
+
expandedHit.fullscreen === isToolTuiFullscreen() &&
|
|
406
|
+
expandedHit.paints.length === childPaints.length &&
|
|
407
|
+
expandedHit.paints.every((paint, index) => paint === childPaints[index])
|
|
408
|
+
) {
|
|
409
|
+
return expandedHit.lines;
|
|
410
|
+
}
|
|
411
|
+
}
|
|
452
412
|
const expandedLines: string[] = [];
|
|
453
413
|
for (let index = 0; index < total; index++) {
|
|
454
414
|
const tool = this.children[index];
|
|
@@ -460,17 +420,19 @@ export class ToolGroupComponent extends Container {
|
|
|
460
420
|
const summary = toolSummary(tool);
|
|
461
421
|
const prefix = ` ${fg("dim", branch)} ${fg(color, statusIcon(toolStatus))} `;
|
|
462
422
|
const detail = fg("dim", summary.detail);
|
|
463
|
-
|
|
423
|
+
// 与单工具卡标题同宽,宽屏右侧留白一致
|
|
424
|
+
const rowWidth = toolViewportWidth(width);
|
|
425
|
+
const mainWidth = Math.max(0, rowWidth - visibleWidth(prefix) - visibleWidth(detail));
|
|
464
426
|
lines.push(
|
|
465
427
|
truncateToWidth(
|
|
466
|
-
`${prefix}${
|
|
467
|
-
|
|
428
|
+
`${prefix}${renderToolSummary(summary, mainWidth, fg)}${detail}`,
|
|
429
|
+
rowWidth,
|
|
468
430
|
"",
|
|
469
431
|
),
|
|
470
432
|
);
|
|
471
433
|
continue;
|
|
472
434
|
}
|
|
473
|
-
const rendered = visibleLines(
|
|
435
|
+
const rendered = visibleLines(Array.isArray(childPaints?.[index]) ? childPaints[index] : []);
|
|
474
436
|
if (rendered.length) {
|
|
475
437
|
rendered[0] = stripLeadingStatusIcon(rendered[0])
|
|
476
438
|
.replace(/^ +/, "")
|
|
@@ -479,7 +441,8 @@ export class ToolGroupComponent extends Container {
|
|
|
479
441
|
const childLines = rendered.length ? rendered : [toolSummary(tool).main];
|
|
480
442
|
for (let lineIndex = 0; lineIndex < childLines.length; lineIndex++) {
|
|
481
443
|
const content =
|
|
482
|
-
|
|
444
|
+
// 续行只剥外层 Box 的 1 格 left pad,保留 Input/Output 相对缩进
|
|
445
|
+
lineIndex === 0 ? childLines[lineIndex] : stripLeadingSpaces(childLines[lineIndex], 1);
|
|
483
446
|
const prefix =
|
|
484
447
|
lineIndex === 0
|
|
485
448
|
? `${fg("dim", branch)} ${fg(color, statusIcon(toolStatus))} `
|
|
@@ -494,6 +457,14 @@ export class ToolGroupComponent extends Container {
|
|
|
494
457
|
lines.push(paddedBackgroundRow(theme, backgroundSlot, line, width));
|
|
495
458
|
}
|
|
496
459
|
lines.push(paddedBackgroundRow(theme, backgroundSlot, "", width));
|
|
460
|
+
this.expandedPaintCache = {
|
|
461
|
+
width,
|
|
462
|
+
hover: this.hintHovered,
|
|
463
|
+
theme: this.patch.theme,
|
|
464
|
+
fullscreen: isToolTuiFullscreen(),
|
|
465
|
+
paints: childPaints ?? [],
|
|
466
|
+
lines,
|
|
467
|
+
};
|
|
497
468
|
} else if (counts.pending === 0) {
|
|
498
469
|
this.storeSettledCache(width, lines);
|
|
499
470
|
}
|
|
@@ -520,7 +491,7 @@ function ungroup(patch: Patch): void {
|
|
|
520
491
|
}
|
|
521
492
|
}
|
|
522
493
|
|
|
523
|
-
function normalizeGroup(group: ToolGroupComponent): void {
|
|
494
|
+
function normalizeGroup(patch: Patch, group: ToolGroupComponent): void {
|
|
524
495
|
if (group.children.length > 1) return;
|
|
525
496
|
const parent = (group as any)[PARENT_KEY];
|
|
526
497
|
const index = parent?.children?.indexOf(group) ?? -1;
|
|
@@ -569,32 +540,17 @@ function maybeGroup(patch: Patch, parent: any, component: any): void {
|
|
|
569
540
|
/** /reload 不会重新 addChild;扫描当前 mounted roots,把已有工具重新送入同一分组规则。 */
|
|
570
541
|
function regroup(patch: Patch, root: any): void {
|
|
571
542
|
if (!patch.active || !patch.enabled() || !root) return;
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
if (
|
|
575
|
-
seen.add(value);
|
|
576
|
-
if (Array.isArray(value)) {
|
|
577
|
-
for (const child of value) visit(child);
|
|
578
|
-
return;
|
|
579
|
-
}
|
|
543
|
+
walkComponentTree(root, (value: any) => {
|
|
544
|
+
// 分组卡与可分组工具是分组边界:不继续下钻(与原有遍历过滤一致)。
|
|
545
|
+
if (value instanceof ToolGroupComponent || isGroupable(value)) return false;
|
|
580
546
|
const children = value.children;
|
|
581
547
|
if (Array.isArray(children)) {
|
|
582
548
|
for (const child of [...children]) {
|
|
583
549
|
if (child && typeof child === "object") child[PARENT_KEY] = value;
|
|
584
550
|
maybeGroup(patch, value, child);
|
|
585
551
|
}
|
|
586
|
-
for (const child of [...children]) {
|
|
587
|
-
if (!(child instanceof ToolGroupComponent) && !isGroupable(child)) visit(child);
|
|
588
|
-
}
|
|
589
552
|
}
|
|
590
|
-
|
|
591
|
-
const mounted = value.getMountedRoots?.();
|
|
592
|
-
if (Array.isArray(mounted)) visit(mounted);
|
|
593
|
-
} catch {
|
|
594
|
-
// renderer 切换中的惰性 Proxy 可能暂时没有 mounted roots。
|
|
595
|
-
}
|
|
596
|
-
};
|
|
597
|
-
visit(root);
|
|
553
|
+
});
|
|
598
554
|
}
|
|
599
555
|
|
|
600
556
|
export type ToolGroupingHooks = {
|
|
@@ -605,8 +561,7 @@ export type ToolGroupingHooks = {
|
|
|
605
561
|
|
|
606
562
|
export function installToolGrouping(getEnabled: () => boolean): ToolGroupingHooks {
|
|
607
563
|
const prototype = Container.prototype as any;
|
|
608
|
-
const
|
|
609
|
-
const previous = host[PATCH_KEY] as Patch | undefined;
|
|
564
|
+
const previous = patchRegistry.get<Patch>(PATCH_KEY);
|
|
610
565
|
if (previous) {
|
|
611
566
|
previous.active = false;
|
|
612
567
|
previous.enabled = () => false;
|
|
@@ -651,12 +606,12 @@ export function installToolGrouping(getEnabled: () => boolean): ToolGroupingHook
|
|
|
651
606
|
const group = component?.[PARENT_KEY];
|
|
652
607
|
if (group instanceof ToolGroupComponent && (group as any)[PARENT_KEY] === this) {
|
|
653
608
|
group.removeTool(component);
|
|
654
|
-
normalizeGroup(group);
|
|
609
|
+
normalizeGroup(patch, group);
|
|
655
610
|
return;
|
|
656
611
|
}
|
|
657
612
|
const result = patch.original.removeChild.call(this, component);
|
|
658
613
|
if (component?.[PARENT_KEY] === this) delete component[PARENT_KEY];
|
|
659
|
-
if (this instanceof ToolGroupComponent) normalizeGroup(this);
|
|
614
|
+
if (this instanceof ToolGroupComponent) normalizeGroup(patch, this);
|
|
660
615
|
if (component instanceof ToolGroupComponent) {
|
|
661
616
|
for (const tool of component.releaseTools()) delete tool[PARENT_KEY];
|
|
662
617
|
}
|
|
@@ -676,7 +631,7 @@ export function installToolGrouping(getEnabled: () => boolean): ToolGroupingHook
|
|
|
676
631
|
prototype.addChild = patch.installed.addChild;
|
|
677
632
|
prototype.removeChild = patch.installed.removeChild;
|
|
678
633
|
prototype.clear = patch.installed.clear;
|
|
679
|
-
|
|
634
|
+
patchRegistry.install(PATCH_KEY, patch);
|
|
680
635
|
return {
|
|
681
636
|
setTheme(theme: any) {
|
|
682
637
|
patch.theme = theme;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { humanizeToolLabel } from "./names.ts";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* MCP 工具的识别与标题,单卡(default-mode)与分组行/分组头(grouping)共用。
|
|
5
|
+
*
|
|
6
|
+
* - 判定:工具名带 mcp 片段(`mcp` 网关、`mcpScript`、`mcp__<server>`),或 adapter 注册时
|
|
7
|
+
* 给的 label 以 `MCP:` 开头。默认/none/short 前缀模式下直连工具的名字里没有 mcp 片段
|
|
8
|
+
* (`github_search_code`、`search_code`),只能靠 label 判定。
|
|
9
|
+
* - 标题:具体工具用 adapter 暴露的真实工具名,不做二次格式化;只有 `mcp` / `mcpScript`
|
|
10
|
+
* 这两个入口没有具体工具名,跟普通工具一样人性化(MCP / MCP Script)。
|
|
11
|
+
* - 参数摘要与其它工具共用 toolCallSummary 的字段链,网关额外把 `args.tool` 提到标题后。
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/** 单次 MCP 调用的识别信息。 */
|
|
15
|
+
export type McpToolCall = {
|
|
16
|
+
toolName: string;
|
|
17
|
+
/** 工具定义;默认/none/short 前缀模式要靠 label 判定,会话重放时可能缺失。 */
|
|
18
|
+
definition?: any;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const GATEWAY_TOOL_NAME = "mcp";
|
|
22
|
+
const SCRIPT_TOOL_NAME = "mcpScript";
|
|
23
|
+
|
|
24
|
+
export function isMcpToolDefinition(definition: any, toolName: string): boolean {
|
|
25
|
+
const label = typeof definition?.label === "string" ? definition.label.trim() : "";
|
|
26
|
+
if (/^MCP(?::|$)/i.test(label)) return true;
|
|
27
|
+
if (toolName === GATEWAY_TOOL_NAME || toolName === SCRIPT_TOOL_NAME) return true;
|
|
28
|
+
return /^mcp[_:-]|[_:-]mcp[_:-]/i.test(toolName);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** 标题:MCP 工具返回标题(入口走人性化,其余用真实工具名);非 MCP 返回 undefined。 */
|
|
32
|
+
export function mcpToolTitle(call: McpToolCall): string | undefined {
|
|
33
|
+
const { toolName } = call;
|
|
34
|
+
if (!isMcpToolDefinition(call.definition, toolName)) return undefined;
|
|
35
|
+
if (toolName === GATEWAY_TOOL_NAME || toolName === SCRIPT_TOOL_NAME) {
|
|
36
|
+
return humanizeToolLabel(toolName);
|
|
37
|
+
}
|
|
38
|
+
return toolName;
|
|
39
|
+
}
|