pi-tool-display 0.1.5 → 0.1.7

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/CHANGELOG.md CHANGED
@@ -7,6 +7,29 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.1.7] - 2026-03-07
11
+
12
+ ### Added
13
+ - Added line-width safety utilities for diff rendering so collapsed and expanded diff output can be clamped to the current pane width.
14
+ - Added utility test coverage for write display helpers, native user message box helpers, and narrow-width diff hint behavior.
15
+
16
+ ### Changed
17
+ - Updated README documentation to reflect the current command surface, config model, width-safe diff behavior, native user message box pipeline, and project structure.
18
+ - Refactored native user message box rendering into focused markdown, patching, renderer, and ANSI/background utility modules.
19
+
20
+ ### Fixed
21
+ - Prevented diff rendering and collapsed diff hints from overflowing narrow terminal widths by progressively shortening hint text and clamping rendered lines.
22
+ - Preserved inline `write` call summaries with line-count and byte-size metadata when content is available.
23
+ - Prevented thinking label presentation changes from leaking into future assistant context by sanitizing stored thinking blocks during the `context` extension event.
24
+ - Hardened thinking label normalization to strip ANSI residue fragments such as `38;5;208m` before display formatting.
25
+ - Restored final-message thinking label persistence on `message_end` so themed labels remain consistent after streaming and across session reloads.
26
+ - Improved native user message box rendering so markdown content, ANSI-only blank lines, and background fill behave more consistently.
27
+
28
+ ## [0.1.6] - 2026-03-04
29
+
30
+ ### Fixed
31
+ - Use absolute GitHub raw URL for README image to fix npm display
32
+
10
33
  ## [0.1.5] - 2026-03-04
11
34
 
12
35
  ### Added
package/README.md CHANGED
@@ -2,24 +2,25 @@
2
2
 
3
3
  OpenCode-style tool rendering for the [Pi coding agent](https://github.com/mariozechner/pi).
4
4
 
5
- `pi-tool-display` provides compact, expandable tool call/result rendering that keeps your terminal clean while preserving access to full details when needed.
5
+ `pi-tool-display` keeps tool calls compact by default, adds richer diff rendering for file edits, and improves a few core chat UI details such as thinking labels and the native user prompt box.
6
6
 
7
- ![Screenshot](assets/pi-tool-display.png)
7
+ ![Screenshot](https://raw.githubusercontent.com/MasuRii/pi-tool-display/main/assets/pi-tool-display.png)
8
8
 
9
9
  ## Features
10
10
 
11
- - **Compact Tool Rendering** Overrides built-in `read`, `grep`, `find`, `ls`, `bash`, `edit`, and `write` tools with collapsed-by-default output
12
- - **MCP Tool Support** Custom rendering for MCP gateway tool calls with configurable verbosity
13
- - **Rich Diff Display** Adaptive split/unified diff views with syntax highlighting and inline change emphasis for `edit` and `write` operations
14
- - **Three Presets** Quick verbosity profiles: `opencode` (minimal), `balanced` (summaries), `verbose` (previews)
15
- - **Thinking Labels** Prefixes AI thinking blocks with themed labels for better readability
16
- - **Native User Message Box** Bordered user prompt styling (optional)
17
- - **Extension Compatibility** Per-tool ownership toggles to avoid conflicts with other extensions
18
- - **Capability Detection** Auto-hides MCP/RTK settings when those features aren't available
11
+ - **Compact built-in tool rendering** for `read`, `grep`, `find`, `ls`, `bash`, `edit`, and `write`
12
+ - **MCP-aware rendering** with hidden, summary, and preview modes
13
+ - **Adaptive edit/write diffs** with split or unified layouts, syntax highlighting, inline emphasis, and narrow-pane width clamping
14
+ - **Progressive collapsed diff hints** that shorten automatically on small terminal widths instead of overflowing
15
+ - **Three presets**: `opencode`, `balanced`, and `verbose`
16
+ - **Thinking labels** during streaming and final message rendering, with context sanitization to avoid leaking presentation labels back into future model turns
17
+ - **Optional native user message box** with markdown-aware rendering and safer ANSI/background handling
18
+ - **Per-tool ownership toggles** so this extension can coexist with other renderer extensions
19
+ - **Capability-aware settings** that automatically hide MCP and RTK-specific controls when those features are unavailable
19
20
 
20
21
  ## Installation
21
22
 
22
- ### Local Extension Folder
23
+ ### Local extension folder
23
24
 
24
25
  Place this folder in one of Pi's auto-discovery locations:
25
26
 
@@ -31,13 +32,13 @@ Place this folder in one of Pi's auto-discovery locations:
31
32
  .pi/extensions/pi-tool-display
32
33
  ```
33
34
 
34
- ### npm Package
35
+ ### npm package
35
36
 
36
37
  ```bash
37
38
  pi install npm:pi-tool-display
38
39
  ```
39
40
 
40
- ### Git Repository
41
+ ### Git repository
41
42
 
42
43
  ```bash
43
44
  pi install git:github.com/MasuRii/pi-tool-display
@@ -45,7 +46,7 @@ pi install git:github.com/MasuRii/pi-tool-display
45
46
 
46
47
  ## Usage
47
48
 
48
- ### Interactive Settings
49
+ ### Interactive settings
49
50
 
50
51
  Open the settings modal:
51
52
 
@@ -53,11 +54,24 @@ Open the settings modal:
53
54
  /tool-display
54
55
  ```
55
56
 
56
- ### Direct Commands
57
+ The modal exposes the day-to-day controls most people change regularly:
58
+
59
+ - preset profile
60
+ - read output mode
61
+ - grep/find/ls output mode
62
+ - MCP output mode (when MCP is available)
63
+ - preview line count
64
+ - bash collapsed line count
65
+ - diff layout mode
66
+ - native user message box toggle
67
+
68
+ Advanced options remain in `config.json`.
69
+
70
+ ### Direct commands
57
71
 
58
72
  ```text
59
- /tool-display show # Display current configuration
60
- /tool-display reset # Reset to default settings
73
+ /tool-display show # Show the effective config summary
74
+ /tool-display reset # Reset to the default opencode preset
61
75
  /tool-display preset opencode # Apply opencode preset
62
76
  /tool-display preset balanced # Apply balanced preset
63
77
  /tool-display preset verbose # Apply verbose preset
@@ -71,9 +85,9 @@ Open the settings modal:
71
85
  | `balanced` | summary | count | summary | 8 | 10 |
72
86
  | `verbose` | preview | preview | preview | 12 | 20 |
73
87
 
74
- **opencode** (default) Minimal inline-only display; tool results stay collapsed
75
- **balanced** Compact summaries showing line counts and match totals
76
- **verbose** Expanded previews with more visible content by default
88
+ - **`opencode`** (default): minimal inline-only display; tool results stay collapsed
89
+ - **`balanced`**: compact summaries with line counts and match totals
90
+ - **`verbose`**: larger previews for read/search/MCP output and more visible bash output
77
91
 
78
92
  ## Configuration
79
93
 
@@ -83,30 +97,30 @@ Runtime configuration is stored at:
83
97
  ~/.pi/agent/extensions/pi-tool-display/config.json
84
98
  ```
85
99
 
86
- A starter template is available at `config/config.example.json`.
100
+ A starter template is included at `config/config.example.json`.
87
101
 
88
- ### Configuration Options
102
+ ### Configuration options
89
103
 
90
104
  | Option | Type | Default | Description |
91
105
  |--------|------|---------|-------------|
92
- | `registerToolOverrides` | object | all `true` | Per-tool ownership flags (see below) |
93
- | `enableNativeUserMessageBox` | boolean | `true` | Enable bordered user message styling |
106
+ | `registerToolOverrides` | object | all `true` | Per-tool ownership flags |
107
+ | `enableNativeUserMessageBox` | boolean | `true` | Enable bordered user prompt rendering |
94
108
  | `readOutputMode` | string | `"hidden"` | `hidden`, `summary`, or `preview` |
95
109
  | `searchOutputMode` | string | `"hidden"` | `hidden`, `count`, or `preview` |
96
110
  | `mcpOutputMode` | string | `"hidden"` | `hidden`, `summary`, or `preview` |
97
- | `previewLines` | number | `8` | Lines shown in collapsed preview |
98
- | `expandedPreviewMaxLines` | number | `4000` | Max lines when expanded |
99
- | `bashCollapsedLines` | number | `10` | Lines shown for bash output |
111
+ | `previewLines` | number | `8` | Lines shown in collapsed preview mode |
112
+ | `expandedPreviewMaxLines` | number | `4000` | Max preview lines when fully expanded |
113
+ | `bashCollapsedLines` | number | `10` | Lines shown for collapsed bash output |
100
114
  | `diffViewMode` | string | `"auto"` | `auto`, `split`, or `unified` |
101
- | `diffSplitMinWidth` | number | `120` | Minimum terminal width for split view |
102
- | `diffCollapsedLines` | number | `24` | Lines shown in collapsed diff |
103
- | `diffWordWrap` | boolean | `true` | Wrap long lines in diff view |
104
- | `showTruncationHints` | boolean | `true` | Show truncation indicators |
105
- | `showRtkCompactionHints` | boolean | `true` | Show RTK compaction hints |
115
+ | `diffSplitMinWidth` | number | `120` | Minimum width before auto mode prefers split diffs |
116
+ | `diffCollapsedLines` | number | `24` | Diff lines shown before collapsing |
117
+ | `diffWordWrap` | boolean | `true` | Wrap long diff lines when needed |
118
+ | `showTruncationHints` | boolean | `true` | Show truncation indicators for compacted output |
119
+ | `showRtkCompactionHints` | boolean | `true` | Show RTK compaction hints when RTK metadata exists |
106
120
 
107
- ### Tool Override Ownership
121
+ ### Tool ownership
108
122
 
109
- Control which tools this extension overrides:
123
+ Use `registerToolOverrides` to control which built-in tools this extension owns:
110
124
 
111
125
  ```json
112
126
  {
@@ -122,11 +136,11 @@ Control which tools this extension overrides:
122
136
  }
123
137
  ```
124
138
 
125
- Set any tool to `false` to leave rendering ownership to another extension.
139
+ Set any entry to `false` if another extension should handle that tool instead.
126
140
 
127
- > **Note:** Changes to tool ownership require `/reload` to take effect.
141
+ > Changes to tool ownership take effect after `/reload`.
128
142
 
129
- ### Example Configuration
143
+ ### Example config
130
144
 
131
145
  ```json
132
146
  {
@@ -155,55 +169,85 @@ Set any tool to `false` to leave rendering ownership to another extension.
155
169
  }
156
170
  ```
157
171
 
158
- ## Capability Detection
172
+ ## Rendering notes
173
+
174
+ ### Edit and write diffs
175
+
176
+ `edit` and `write` results use the same diff renderer. In `auto` mode the extension chooses split or unified layout based on available width. On narrow panes it clamps rendered lines and shortens collapsed hint text so the diff stays readable instead of spilling past the terminal width.
177
+
178
+ ### Write summaries
179
+
180
+ When content is available, `write` call summaries include line count and byte size information inline so you can quickly see the size of the pending write before expanding the result.
181
+
182
+ ### Thinking labels
159
183
 
160
- The extension automatically detects available capabilities:
184
+ Thinking blocks are labeled during streaming and on final messages. Before the next model turn, the extension sanitizes those presentation labels out of the stored assistant context so they do not accumulate or pollute future prompts.
161
185
 
162
- - **MCP Tooling** When no MCP tools are available, MCP-related settings are hidden and MCP output mode is forced to `hidden`
163
- - **RTK Optimizer** — When [pi-rtk-optimizer](https://github.com/MasuRii/pi-rtk-optimizer) isn't installed, RTK compaction hint settings are hidden and hints are disabled
186
+ ### Native user message box
164
187
 
165
- This prevents confusion from settings that have no effect in your environment.
188
+ When enabled, user prompts render inside a bordered box using Pi's native user message component. The renderer preserves markdown content more safely and normalizes ANSI/background handling to avoid odd nested background artifacts.
189
+
190
+ ## Capability detection
191
+
192
+ The extension checks the current Pi environment and adjusts behavior automatically:
193
+
194
+ - **MCP tooling unavailable**: MCP settings are hidden and MCP output is forced off
195
+ - **RTK optimizer unavailable**: RTK hint settings are hidden and RTK compaction hints are disabled
196
+
197
+ This keeps the UI aligned with what the current environment can actually support.
166
198
 
167
199
  ## Troubleshooting
168
200
 
169
- ### Tool Ownership Conflicts
201
+ ### Tool ownership conflicts
170
202
 
171
- If another extension owns a tool and you see rendering conflicts:
203
+ If another extension is already rendering one of the built-in tools:
172
204
 
173
- 1. Set the corresponding `registerToolOverrides.<tool>` to `false` in your config
174
- 2. Run `/reload` in Pi
175
- 3. Verify with `/tool-display show` that the ownership reflects expected `off` values
205
+ 1. Set `registerToolOverrides.<tool>` to `false`
206
+ 2. Run `/reload`
207
+ 3. Use `/tool-display show` to confirm the effective ownership state
176
208
 
177
- ### Configuration Not Loading
209
+ ### Config not loading
178
210
 
179
- If settings aren't applying:
211
+ If your settings are not being applied:
180
212
 
181
- 1. Check the config file exists at `~/.pi/agent/extensions/pi-tool-display/config.json`
182
- 2. Verify JSON syntax is valid
183
- 3. Run `/tool-display show` to see current effective configuration
213
+ 1. Check that `~/.pi/agent/extensions/pi-tool-display/config.json` exists
214
+ 2. Make sure the JSON is valid
215
+ 3. Run `/tool-display show` to inspect the effective config summary
184
216
 
185
- ## Project Structure
217
+ ### MCP or RTK settings missing
218
+
219
+ Those controls only appear when the corresponding capability is available in the current Pi environment.
220
+
221
+ ## Project structure
186
222
 
187
223
  ```text
188
224
  pi-tool-display/
189
- ├── index.ts # Extension entrypoint (Pi auto-discovery)
225
+ ├── index.ts # Extension entrypoint for Pi auto-discovery
190
226
  ├── src/
191
- │ ├── index.ts # Extension bootstrap and registration
192
- │ ├── tool-overrides.ts # Built-in and MCP renderer overrides
193
- │ ├── diff-renderer.ts # Edit/write diff rendering engine
194
- │ ├── config-modal.ts # /tool-display settings UI
195
- │ ├── capabilities.ts # MCP/RTK capability detection
196
- │ ├── config-store.ts # Config load/save and normalization
197
- │ ├── presets.ts # Preset definitions and matching
198
- │ ├── render-utils.ts # Shared rendering helpers
199
- │ ├── thinking-label.ts # Thinking block label formatting
200
- │ ├── user-message-box-native.ts # User message border styling
201
- │ ├── types.ts # TypeScript type definitions
202
- └── zellij-modal.ts # Modal UI primitives
227
+ │ ├── index.ts # Bootstrap and extension registration
228
+ │ ├── capabilities.ts # MCP/RTK capability detection
229
+ │ ├── config-modal.ts # /tool-display settings UI and command handling
230
+ │ ├── config-store.ts # Config load/save and normalization
231
+ │ ├── diff-renderer.ts # Edit/write diff rendering engine
232
+ │ ├── line-width-safety.ts # Width clamping helpers for narrow panes
233
+ │ ├── presets.ts # Preset definitions and matching
234
+ │ ├── render-utils.ts # Shared rendering helpers
235
+ │ ├── thinking-label.ts # Thinking label formatting and context sanitization
236
+ │ ├── tool-overrides.ts # Built-in and MCP renderer overrides
237
+ │ ├── types.ts # Shared config and type definitions
238
+ ├── user-message-box-markdown.ts # Markdown extraction for user message rendering
239
+ │ ├── user-message-box-native.ts # Native user message box registration
240
+ │ ├── user-message-box-patch.ts # Safe native render patching helpers
241
+ │ ├── user-message-box-renderer.ts # User message border renderer
242
+ │ ├── user-message-box-utils.ts # ANSI/background normalization helpers
243
+ │ ├── write-display-utils.ts # Write summary helpers
244
+ │ └── zellij-modal.ts # Modal UI primitives
203
245
  ├── config/
204
- │ └── config.example.json # Starter config template
246
+ │ └── config.example.json # Starter config template
247
+ ├── tests/
248
+ │ └── tool-ui-utils.test.ts # Utility tests for user message and diff helpers
205
249
  └── assets/
206
- └── pi-tool-display.png # README screenshot
250
+ └── pi-tool-display.png # README screenshot
207
251
  ```
208
252
 
209
253
  ## Development
@@ -212,17 +256,14 @@ pi-tool-display/
212
256
  # Type check
213
257
  npm run build
214
258
 
215
- # Lint (same as build)
216
- npm run lint
217
-
218
259
  # Run tests
219
260
  npm run test
220
261
 
221
- # Full check
262
+ # Full verification
222
263
  npm run check
223
264
  ```
224
265
 
225
- ## Related Extensions
266
+ ## Related extensions
226
267
 
227
268
  - [pi-rtk-optimizer](https://github.com/MasuRii/pi-rtk-optimizer) — RTK optimizer for token-efficient source output
228
269
 
@@ -1,24 +1,24 @@
1
- {
2
- "registerToolOverrides": {
3
- "read": true,
4
- "grep": true,
5
- "find": true,
6
- "ls": true,
7
- "bash": true,
8
- "edit": true,
9
- "write": true
10
- },
11
- "enableNativeUserMessageBox": true,
12
- "readOutputMode": "hidden",
13
- "searchOutputMode": "hidden",
14
- "mcpOutputMode": "hidden",
15
- "previewLines": 8,
16
- "expandedPreviewMaxLines": 4000,
17
- "bashCollapsedLines": 10,
18
- "diffViewMode": "auto",
19
- "diffSplitMinWidth": 120,
20
- "diffCollapsedLines": 24,
21
- "diffWordWrap": true,
22
- "showTruncationHints": true,
23
- "showRtkCompactionHints": true
24
- }
1
+ {
2
+ "registerToolOverrides": {
3
+ "read": true,
4
+ "grep": true,
5
+ "find": true,
6
+ "ls": true,
7
+ "bash": true,
8
+ "edit": true,
9
+ "write": true
10
+ },
11
+ "enableNativeUserMessageBox": true,
12
+ "readOutputMode": "hidden",
13
+ "searchOutputMode": "hidden",
14
+ "mcpOutputMode": "hidden",
15
+ "previewLines": 8,
16
+ "expandedPreviewMaxLines": 4000,
17
+ "bashCollapsedLines": 10,
18
+ "diffViewMode": "auto",
19
+ "diffSplitMinWidth": 120,
20
+ "diffCollapsedLines": 24,
21
+ "diffWordWrap": true,
22
+ "showTruncationHints": true,
23
+ "showRtkCompactionHints": true
24
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-tool-display",
3
- "version": "0.1.5",
3
+ "version": "0.1.7",
4
4
  "description": "OpenCode-style tool call/result rendering extension for Pi coding agent.",
5
5
  "type": "module",
6
6
  "main": "./index.ts",
@@ -1,94 +1,94 @@
1
- import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
2
- import { existsSync } from "node:fs";
3
- import { homedir } from "node:os";
4
- import { join } from "node:path";
5
- import type { ToolDisplayConfig } from "./types.js";
6
-
7
- export interface ToolDisplayCapabilities {
8
- hasMcpTooling: boolean;
9
- hasRtkOptimizer: boolean;
10
- }
11
-
12
- function toRecord(value: unknown): Record<string, unknown> {
13
- if (!value || typeof value !== "object" || Array.isArray(value)) {
14
- return {};
15
- }
16
- return value as Record<string, unknown>;
17
- }
18
-
19
- function getTextField(value: unknown, field: string): string | undefined {
20
- const record = toRecord(value);
21
- const raw = record[field];
22
- return typeof raw === "string" && raw.trim().length > 0 ? raw.trim() : undefined;
23
- }
24
-
25
- function isMcpToolCandidate(tool: unknown): boolean {
26
- const name = getTextField(tool, "name");
27
- if (name === "mcp") {
28
- return true;
29
- }
30
-
31
- const label = getTextField(tool, "label");
32
- if (label?.startsWith("MCP ")) {
33
- return true;
34
- }
35
-
36
- const description = getTextField(tool, "description");
37
- return typeof description === "string" && /\bmcp\b/i.test(description);
38
- }
39
-
40
- function hasMcpTooling(pi: ExtensionAPI): boolean {
41
- try {
42
- const allTools = pi.getAllTools();
43
- return allTools.some((tool) => isMcpToolCandidate(tool));
44
- } catch {
45
- return false;
46
- }
47
- }
48
-
49
- function hasRtkCommand(pi: ExtensionAPI): boolean {
50
- try {
51
- const commands = pi.getCommands();
52
- return commands.some((command) => command.name === "rtk" || command.name.startsWith("rtk-"));
53
- } catch {
54
- return false;
55
- }
56
- }
57
-
58
- function hasRtkExtensionPath(cwd: string): boolean {
59
- const candidates = [
60
- join(homedir(), ".pi", "agent", "extensions", "pi-rtk-optimizer"),
61
- join(cwd, ".pi", "extensions", "pi-rtk-optimizer"),
62
- ];
63
-
64
- for (const candidate of candidates) {
65
- try {
66
- if (existsSync(candidate)) {
67
- return true;
68
- }
69
- } catch {
70
- // Ignore filesystem errors and continue probing other candidates.
71
- }
72
- }
73
-
74
- return false;
75
- }
76
-
77
- export function detectToolDisplayCapabilities(pi: ExtensionAPI, cwd: string): ToolDisplayCapabilities {
78
- return {
79
- hasMcpTooling: hasMcpTooling(pi),
80
- hasRtkOptimizer: hasRtkCommand(pi) || hasRtkExtensionPath(cwd),
81
- };
82
- }
83
-
84
- export function applyCapabilityConfigGuards(
85
- config: ToolDisplayConfig,
86
- capabilities: ToolDisplayCapabilities,
87
- ): ToolDisplayConfig {
88
- return {
89
- ...config,
90
- registerToolOverrides: { ...config.registerToolOverrides },
91
- mcpOutputMode: capabilities.hasMcpTooling ? config.mcpOutputMode : "hidden",
92
- showRtkCompactionHints: capabilities.hasRtkOptimizer ? config.showRtkCompactionHints : false,
93
- };
94
- }
1
+ import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
2
+ import { existsSync } from "node:fs";
3
+ import { homedir } from "node:os";
4
+ import { join } from "node:path";
5
+ import type { ToolDisplayConfig } from "./types.js";
6
+
7
+ export interface ToolDisplayCapabilities {
8
+ hasMcpTooling: boolean;
9
+ hasRtkOptimizer: boolean;
10
+ }
11
+
12
+ function toRecord(value: unknown): Record<string, unknown> {
13
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
14
+ return {};
15
+ }
16
+ return value as Record<string, unknown>;
17
+ }
18
+
19
+ function getTextField(value: unknown, field: string): string | undefined {
20
+ const record = toRecord(value);
21
+ const raw = record[field];
22
+ return typeof raw === "string" && raw.trim().length > 0 ? raw.trim() : undefined;
23
+ }
24
+
25
+ function isMcpToolCandidate(tool: unknown): boolean {
26
+ const name = getTextField(tool, "name");
27
+ if (name === "mcp") {
28
+ return true;
29
+ }
30
+
31
+ const label = getTextField(tool, "label");
32
+ if (label?.startsWith("MCP ")) {
33
+ return true;
34
+ }
35
+
36
+ const description = getTextField(tool, "description");
37
+ return typeof description === "string" && /\bmcp\b/i.test(description);
38
+ }
39
+
40
+ function hasMcpTooling(pi: ExtensionAPI): boolean {
41
+ try {
42
+ const allTools = pi.getAllTools();
43
+ return allTools.some((tool) => isMcpToolCandidate(tool));
44
+ } catch {
45
+ return false;
46
+ }
47
+ }
48
+
49
+ function hasRtkCommand(pi: ExtensionAPI): boolean {
50
+ try {
51
+ const commands = pi.getCommands();
52
+ return commands.some((command) => command.name === "rtk" || command.name.startsWith("rtk-"));
53
+ } catch {
54
+ return false;
55
+ }
56
+ }
57
+
58
+ function hasRtkExtensionPath(cwd: string): boolean {
59
+ const candidates = [
60
+ join(homedir(), ".pi", "agent", "extensions", "pi-rtk-optimizer"),
61
+ join(cwd, ".pi", "extensions", "pi-rtk-optimizer"),
62
+ ];
63
+
64
+ for (const candidate of candidates) {
65
+ try {
66
+ if (existsSync(candidate)) {
67
+ return true;
68
+ }
69
+ } catch {
70
+ // Ignore filesystem errors and continue probing other candidates.
71
+ }
72
+ }
73
+
74
+ return false;
75
+ }
76
+
77
+ export function detectToolDisplayCapabilities(pi: ExtensionAPI, cwd: string): ToolDisplayCapabilities {
78
+ return {
79
+ hasMcpTooling: hasMcpTooling(pi),
80
+ hasRtkOptimizer: hasRtkCommand(pi) || hasRtkExtensionPath(cwd),
81
+ };
82
+ }
83
+
84
+ export function applyCapabilityConfigGuards(
85
+ config: ToolDisplayConfig,
86
+ capabilities: ToolDisplayCapabilities,
87
+ ): ToolDisplayConfig {
88
+ return {
89
+ ...config,
90
+ registerToolOverrides: { ...config.registerToolOverrides },
91
+ mcpOutputMode: capabilities.hasMcpTooling ? config.mcpOutputMode : "hidden",
92
+ showRtkCompactionHints: capabilities.hasRtkOptimizer ? config.showRtkCompactionHints : false,
93
+ };
94
+ }