@oh-my-pi/pi-coding-agent 1.340.0 → 2.0.1337
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 +115 -1
- package/README.md +1 -1
- package/examples/custom-tools/subagent/index.ts +1 -1
- package/package.json +5 -3
- package/src/cli/args.ts +13 -6
- package/src/cli/file-processor.ts +3 -3
- package/src/cli/list-models.ts +2 -2
- package/src/cli/plugin-cli.ts +1 -1
- package/src/cli/session-picker.ts +2 -2
- package/src/cli.ts +1 -1
- package/src/config.ts +3 -3
- package/src/core/agent-session.ts +189 -29
- package/src/core/bash-executor.ts +50 -10
- package/src/core/compaction/branch-summarization.ts +5 -5
- package/src/core/compaction/compaction.ts +3 -3
- package/src/core/compaction/index.ts +3 -3
- package/src/core/custom-commands/bundled/review/index.ts +156 -0
- package/src/core/custom-commands/index.ts +15 -0
- package/src/core/custom-commands/loader.ts +232 -0
- package/src/core/custom-commands/types.ts +112 -0
- package/src/core/custom-tools/index.ts +3 -3
- package/src/core/custom-tools/loader.ts +10 -8
- package/src/core/custom-tools/types.ts +11 -6
- package/src/core/custom-tools/wrapper.ts +2 -1
- package/src/core/exec.ts +22 -12
- package/src/core/export-html/index.ts +5 -5
- package/src/core/file-mentions.ts +54 -0
- package/src/core/hooks/index.ts +5 -5
- package/src/core/hooks/loader.ts +21 -16
- package/src/core/hooks/runner.ts +6 -6
- package/src/core/hooks/tool-wrapper.ts +2 -2
- package/src/core/hooks/types.ts +12 -15
- package/src/core/index.ts +6 -6
- package/src/core/logger.ts +112 -0
- package/src/core/mcp/client.ts +3 -3
- package/src/core/mcp/config.ts +1 -1
- package/src/core/mcp/index.ts +12 -12
- package/src/core/mcp/loader.ts +2 -2
- package/src/core/mcp/manager.ts +6 -6
- package/src/core/mcp/tool-bridge.ts +3 -3
- package/src/core/mcp/transports/http.ts +1 -1
- package/src/core/mcp/transports/index.ts +2 -2
- package/src/core/mcp/transports/stdio.ts +1 -1
- package/src/core/messages.ts +22 -0
- package/src/core/model-registry.ts +2 -2
- package/src/core/model-resolver.ts +103 -2
- package/src/core/plugins/doctor.ts +1 -1
- package/src/core/plugins/index.ts +6 -6
- package/src/core/plugins/installer.ts +4 -4
- package/src/core/plugins/loader.ts +4 -9
- package/src/core/plugins/manager.ts +5 -5
- package/src/core/plugins/paths.ts +3 -3
- package/src/core/sdk.ts +127 -52
- package/src/core/session-manager.ts +123 -20
- package/src/core/settings-manager.ts +106 -22
- package/src/core/skills.ts +5 -5
- package/src/core/slash-commands.ts +60 -45
- package/src/core/system-prompt.ts +6 -6
- package/src/core/title-generator.ts +94 -0
- package/src/core/tools/bash.ts +33 -157
- package/src/core/tools/context.ts +2 -2
- package/src/core/tools/edit-diff.ts +5 -5
- package/src/core/tools/edit.ts +60 -9
- package/src/core/tools/exa/company.ts +3 -3
- package/src/core/tools/exa/index.ts +16 -17
- package/src/core/tools/exa/linkedin.ts +3 -3
- package/src/core/tools/exa/mcp-client.ts +9 -9
- package/src/core/tools/exa/render.ts +5 -5
- package/src/core/tools/exa/researcher.ts +3 -3
- package/src/core/tools/exa/search.ts +6 -5
- package/src/core/tools/exa/types.ts +5 -6
- package/src/core/tools/exa/websets.ts +3 -3
- package/src/core/tools/find.ts +3 -3
- package/src/core/tools/grep.ts +6 -5
- package/src/core/tools/index.ts +114 -40
- package/src/core/tools/ls.ts +4 -4
- package/src/core/tools/lsp/client.ts +204 -108
- package/src/core/tools/lsp/config.ts +709 -35
- package/src/core/tools/lsp/edits.ts +2 -2
- package/src/core/tools/lsp/index.ts +432 -30
- package/src/core/tools/lsp/render.ts +2 -2
- package/src/core/tools/lsp/rust-analyzer.ts +3 -3
- package/src/core/tools/lsp/types.ts +5 -0
- package/src/core/tools/lsp/utils.ts +1 -1
- package/src/core/tools/notebook.ts +1 -1
- package/src/core/tools/output.ts +175 -0
- package/src/core/tools/read.ts +7 -7
- package/src/core/tools/renderers.ts +92 -13
- package/src/core/tools/review.ts +268 -0
- package/src/core/tools/task/agents.ts +1 -1
- package/src/core/tools/task/bundled-agents/explore.md +1 -1
- package/src/core/tools/task/bundled-agents/reviewer.md +53 -38
- package/src/core/tools/task/discovery.ts +2 -2
- package/src/core/tools/task/executor.ts +145 -28
- package/src/core/tools/task/index.ts +78 -30
- package/src/core/tools/task/model-resolver.ts +72 -13
- package/src/core/tools/task/parallel.ts +1 -1
- package/src/core/tools/task/render.ts +219 -30
- package/src/core/tools/task/subprocess-tool-registry.ts +89 -0
- package/src/core/tools/task/types.ts +36 -2
- package/src/core/tools/web-fetch.ts +5 -3
- package/src/core/tools/web-search/auth.ts +1 -1
- package/src/core/tools/web-search/index.ts +17 -15
- package/src/core/tools/web-search/providers/anthropic.ts +2 -2
- package/src/core/tools/web-search/providers/exa.ts +3 -5
- package/src/core/tools/web-search/providers/perplexity.ts +1 -1
- package/src/core/tools/web-search/render.ts +3 -3
- package/src/core/tools/write.ts +70 -7
- package/src/index.ts +33 -17
- package/src/main.ts +60 -34
- package/src/migrations.ts +3 -3
- package/src/modes/index.ts +5 -5
- package/src/modes/interactive/components/armin.ts +1 -1
- package/src/modes/interactive/components/assistant-message.ts +1 -1
- package/src/modes/interactive/components/bash-execution.ts +4 -4
- package/src/modes/interactive/components/bordered-loader.ts +2 -2
- package/src/modes/interactive/components/branch-summary-message.ts +2 -2
- package/src/modes/interactive/components/compaction-summary-message.ts +2 -2
- package/src/modes/interactive/components/diff.ts +1 -1
- package/src/modes/interactive/components/dynamic-border.ts +1 -1
- package/src/modes/interactive/components/footer.ts +5 -5
- package/src/modes/interactive/components/hook-editor.ts +2 -2
- package/src/modes/interactive/components/hook-input.ts +2 -2
- package/src/modes/interactive/components/hook-message.ts +3 -3
- package/src/modes/interactive/components/hook-selector.ts +2 -2
- package/src/modes/interactive/components/model-selector.ts +341 -41
- package/src/modes/interactive/components/oauth-selector.ts +3 -3
- package/src/modes/interactive/components/plugin-settings.ts +4 -4
- package/src/modes/interactive/components/queue-mode-selector.ts +2 -2
- package/src/modes/interactive/components/session-selector.ts +24 -11
- package/src/modes/interactive/components/settings-defs.ts +51 -3
- package/src/modes/interactive/components/settings-selector.ts +13 -16
- package/src/modes/interactive/components/show-images-selector.ts +2 -2
- package/src/modes/interactive/components/theme-selector.ts +2 -2
- package/src/modes/interactive/components/thinking-selector.ts +2 -2
- package/src/modes/interactive/components/tool-execution.ts +44 -8
- package/src/modes/interactive/components/tree-selector.ts +5 -5
- package/src/modes/interactive/components/user-message-selector.ts +2 -2
- package/src/modes/interactive/components/user-message.ts +1 -1
- package/src/modes/interactive/components/welcome.ts +42 -5
- package/src/modes/interactive/interactive-mode.ts +169 -48
- package/src/modes/interactive/theme/theme.ts +8 -7
- package/src/modes/print-mode.ts +4 -3
- package/src/modes/rpc/rpc-client.ts +4 -4
- package/src/modes/rpc/rpc-mode.ts +21 -11
- package/src/modes/rpc/rpc-types.ts +3 -3
- package/src/utils/changelog.ts +2 -2
- package/src/utils/clipboard.ts +1 -1
- package/src/utils/shell-snapshot.ts +218 -0
- package/src/utils/shell.ts +93 -13
- package/src/utils/tools-manager.ts +1 -1
- package/examples/custom-tools/subagent/agents/reviewer.md +0 -35
- package/src/core/tools/exa/logger.ts +0 -56
|
@@ -11,10 +11,10 @@ import {
|
|
|
11
11
|
Text,
|
|
12
12
|
truncateToWidth,
|
|
13
13
|
} from "@oh-my-pi/pi-tui";
|
|
14
|
-
import type { SessionInfo } from "../../../core/session-manager
|
|
15
|
-
import { fuzzyFilter } from "../../../utils/fuzzy
|
|
16
|
-
import { theme } from "../theme/theme
|
|
17
|
-
import { DynamicBorder } from "./dynamic-border
|
|
14
|
+
import type { SessionInfo } from "../../../core/session-manager";
|
|
15
|
+
import { fuzzyFilter } from "../../../utils/fuzzy";
|
|
16
|
+
import { theme } from "../theme/theme";
|
|
17
|
+
import { DynamicBorder } from "./dynamic-border";
|
|
18
18
|
|
|
19
19
|
/**
|
|
20
20
|
* Custom session list component with multi-line items and search
|
|
@@ -90,7 +90,7 @@ class SessionList implements Component {
|
|
|
90
90
|
);
|
|
91
91
|
const endIndex = Math.min(startIndex + this.maxVisible, this.filteredSessions.length);
|
|
92
92
|
|
|
93
|
-
// Render visible sessions (2 lines per session + blank line)
|
|
93
|
+
// Render visible sessions (2-3 lines per session + blank line)
|
|
94
94
|
for (let i = startIndex; i < endIndex; i++) {
|
|
95
95
|
const session = this.filteredSessions[i];
|
|
96
96
|
const isSelected = i === this.selectedIndex;
|
|
@@ -98,19 +98,32 @@ class SessionList implements Component {
|
|
|
98
98
|
// Normalize first message to single line
|
|
99
99
|
const normalizedMessage = session.firstMessage.replace(/\n/g, " ").trim();
|
|
100
100
|
|
|
101
|
-
// First line: cursor +
|
|
101
|
+
// First line: cursor + title (or first message if no title)
|
|
102
102
|
const cursor = isSelected ? theme.fg("accent", "› ") : " ";
|
|
103
|
-
const
|
|
104
|
-
|
|
105
|
-
|
|
103
|
+
const maxWidth = width - 2; // Account for cursor (2 visible chars)
|
|
104
|
+
|
|
105
|
+
if (session.title) {
|
|
106
|
+
// Has title: show title on first line, dimmed first message on second line
|
|
107
|
+
const truncatedTitle = truncateToWidth(session.title, maxWidth, "...");
|
|
108
|
+
const titleLine = cursor + (isSelected ? theme.bold(truncatedTitle) : truncatedTitle);
|
|
109
|
+
lines.push(titleLine);
|
|
110
|
+
|
|
111
|
+
// Second line: dimmed first message preview
|
|
112
|
+
const truncatedPreview = truncateToWidth(normalizedMessage, maxWidth, "...");
|
|
113
|
+
lines.push(` ${theme.fg("dim", truncatedPreview)}`);
|
|
114
|
+
} else {
|
|
115
|
+
// No title: show first message as main line
|
|
116
|
+
const truncatedMsg = truncateToWidth(normalizedMessage, maxWidth, "...");
|
|
117
|
+
const messageLine = cursor + (isSelected ? theme.bold(truncatedMsg) : truncatedMsg);
|
|
118
|
+
lines.push(messageLine);
|
|
119
|
+
}
|
|
106
120
|
|
|
107
|
-
//
|
|
121
|
+
// Metadata line: date + message count
|
|
108
122
|
const modified = formatDate(session.modified);
|
|
109
123
|
const msgCount = `${session.messageCount} message${session.messageCount !== 1 ? "s" : ""}`;
|
|
110
124
|
const metadata = ` ${modified} · ${msgCount}`;
|
|
111
125
|
const metadataLine = theme.fg("dim", truncateToWidth(metadata, width, ""));
|
|
112
126
|
|
|
113
|
-
lines.push(messageLine);
|
|
114
127
|
lines.push(metadataLine);
|
|
115
128
|
lines.push(""); // Blank line between sessions
|
|
116
129
|
}
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
import type { ThinkingLevel } from "@oh-my-pi/pi-agent-core";
|
|
12
12
|
import { getCapabilities } from "@oh-my-pi/pi-tui";
|
|
13
|
-
import type { SettingsManager } from "../../../core/settings-manager
|
|
13
|
+
import type { SettingsManager } from "../../../core/settings-manager";
|
|
14
14
|
|
|
15
15
|
// Setting value types
|
|
16
16
|
export type SettingValue = boolean | string;
|
|
@@ -20,7 +20,7 @@ interface BaseSettingDef {
|
|
|
20
20
|
id: string;
|
|
21
21
|
label: string;
|
|
22
22
|
description: string;
|
|
23
|
-
tab:
|
|
23
|
+
tab: string;
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
// Boolean toggle setting
|
|
@@ -99,6 +99,16 @@ export const SETTINGS_DEFS: SettingDef[] = [
|
|
|
99
99
|
get: (sm) => sm.getQueueMode(),
|
|
100
100
|
set: (sm, v) => sm.setQueueMode(v as "all" | "one-at-a-time"), // Also handled in session
|
|
101
101
|
},
|
|
102
|
+
{
|
|
103
|
+
id: "interruptMode",
|
|
104
|
+
tab: "config",
|
|
105
|
+
type: "enum",
|
|
106
|
+
label: "Interrupt mode",
|
|
107
|
+
description: "When to process queued messages: immediately (interrupt tools) or wait for turn to complete",
|
|
108
|
+
values: ["immediate", "wait"],
|
|
109
|
+
get: (sm) => sm.getInterruptMode(),
|
|
110
|
+
set: (sm, v) => sm.setInterruptMode(v as "immediate" | "wait"), // Also handled in session
|
|
111
|
+
},
|
|
102
112
|
{
|
|
103
113
|
id: "hideThinking",
|
|
104
114
|
tab: "config",
|
|
@@ -135,6 +145,15 @@ export const SETTINGS_DEFS: SettingDef[] = [
|
|
|
135
145
|
get: (sm) => sm.getMCPProjectConfigEnabled(),
|
|
136
146
|
set: (sm, v) => sm.setMCPProjectConfigEnabled(v),
|
|
137
147
|
},
|
|
148
|
+
{
|
|
149
|
+
id: "editFuzzyMatch",
|
|
150
|
+
tab: "config",
|
|
151
|
+
type: "boolean",
|
|
152
|
+
label: "Edit fuzzy match",
|
|
153
|
+
description: "Accept high-confidence fuzzy matches for whitespace/indentation differences",
|
|
154
|
+
get: (sm) => sm.getEditFuzzyMatch(),
|
|
155
|
+
set: (sm, v) => sm.setEditFuzzyMatch(v),
|
|
156
|
+
},
|
|
138
157
|
{
|
|
139
158
|
id: "thinkingLevel",
|
|
140
159
|
tab: "config",
|
|
@@ -161,6 +180,35 @@ export const SETTINGS_DEFS: SettingDef[] = [
|
|
|
161
180
|
getOptions: () => [], // Filled dynamically from context
|
|
162
181
|
},
|
|
163
182
|
|
|
183
|
+
// LSP tab
|
|
184
|
+
{
|
|
185
|
+
id: "lspFormatOnWrite",
|
|
186
|
+
tab: "lsp",
|
|
187
|
+
type: "boolean",
|
|
188
|
+
label: "Format on write",
|
|
189
|
+
description: "Automatically format code files using LSP after writing",
|
|
190
|
+
get: (sm) => sm.getLspFormatOnWrite(),
|
|
191
|
+
set: (sm, v) => sm.setLspFormatOnWrite(v),
|
|
192
|
+
},
|
|
193
|
+
{
|
|
194
|
+
id: "lspDiagnosticsOnWrite",
|
|
195
|
+
tab: "lsp",
|
|
196
|
+
type: "boolean",
|
|
197
|
+
label: "Diagnostics on write",
|
|
198
|
+
description: "Return LSP diagnostics (errors/warnings) after writing code files",
|
|
199
|
+
get: (sm) => sm.getLspDiagnosticsOnWrite(),
|
|
200
|
+
set: (sm, v) => sm.setLspDiagnosticsOnWrite(v),
|
|
201
|
+
},
|
|
202
|
+
{
|
|
203
|
+
id: "lspDiagnosticsOnEdit",
|
|
204
|
+
tab: "lsp",
|
|
205
|
+
type: "boolean",
|
|
206
|
+
label: "Diagnostics on edit",
|
|
207
|
+
description: "Return LSP diagnostics (errors/warnings) after editing code files",
|
|
208
|
+
get: (sm) => sm.getLspDiagnosticsOnEdit(),
|
|
209
|
+
set: (sm, v) => sm.setLspDiagnosticsOnEdit(v),
|
|
210
|
+
},
|
|
211
|
+
|
|
164
212
|
// Exa tab
|
|
165
213
|
{
|
|
166
214
|
id: "exaEnabled",
|
|
@@ -219,7 +267,7 @@ export const SETTINGS_DEFS: SettingDef[] = [
|
|
|
219
267
|
];
|
|
220
268
|
|
|
221
269
|
/** Get settings for a specific tab */
|
|
222
|
-
export function getSettingsForTab(tab:
|
|
270
|
+
export function getSettingsForTab(tab: string): SettingDef[] {
|
|
223
271
|
return SETTINGS_DEFS.filter((def) => def.tab === tab);
|
|
224
272
|
}
|
|
225
273
|
|
|
@@ -16,11 +16,11 @@ import {
|
|
|
16
16
|
type TabBarTheme,
|
|
17
17
|
Text,
|
|
18
18
|
} from "@oh-my-pi/pi-tui";
|
|
19
|
-
import type { SettingsManager } from "../../../core/settings-manager
|
|
20
|
-
import { getSelectListTheme, getSettingsListTheme, theme } from "../theme/theme
|
|
21
|
-
import { DynamicBorder } from "./dynamic-border
|
|
22
|
-
import { PluginSettingsComponent } from "./plugin-settings
|
|
23
|
-
import { getSettingsForTab, type SettingDef } from "./settings-defs
|
|
19
|
+
import type { SettingsManager } from "../../../core/settings-manager";
|
|
20
|
+
import { getSelectListTheme, getSettingsListTheme, theme } from "../theme/theme";
|
|
21
|
+
import { DynamicBorder } from "./dynamic-border";
|
|
22
|
+
import { PluginSettingsComponent } from "./plugin-settings";
|
|
23
|
+
import { getSettingsForTab, type SettingDef } from "./settings-defs";
|
|
24
24
|
|
|
25
25
|
function getTabBarTheme(): TabBarTheme {
|
|
26
26
|
return {
|
|
@@ -93,10 +93,11 @@ class SelectSubmenu extends Container {
|
|
|
93
93
|
}
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
-
type TabId =
|
|
96
|
+
type TabId = string;
|
|
97
97
|
|
|
98
98
|
const SETTINGS_TABS: Tab[] = [
|
|
99
99
|
{ id: "config", label: "Config" },
|
|
100
|
+
{ id: "lsp", label: "LSP" },
|
|
100
101
|
{ id: "exa", label: "Exa" },
|
|
101
102
|
{ id: "plugins", label: "Plugins" },
|
|
102
103
|
];
|
|
@@ -189,14 +190,10 @@ export class SettingsSelectorComponent extends Container {
|
|
|
189
190
|
const bottomBorder = this.children[this.children.length - 1];
|
|
190
191
|
this.removeChild(bottomBorder);
|
|
191
192
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
break;
|
|
197
|
-
case "plugins":
|
|
198
|
-
this.showPluginsTab();
|
|
199
|
-
break;
|
|
193
|
+
if (tabId === "plugins") {
|
|
194
|
+
this.showPluginsTab();
|
|
195
|
+
} else {
|
|
196
|
+
this.showSettingsTab(tabId);
|
|
200
197
|
}
|
|
201
198
|
|
|
202
199
|
// Re-add bottom border
|
|
@@ -301,9 +298,9 @@ export class SettingsSelectorComponent extends Container {
|
|
|
301
298
|
}
|
|
302
299
|
|
|
303
300
|
/**
|
|
304
|
-
* Show a settings tab
|
|
301
|
+
* Show a settings tab using definitions.
|
|
305
302
|
*/
|
|
306
|
-
private showSettingsTab(tabId:
|
|
303
|
+
private showSettingsTab(tabId: string): void {
|
|
307
304
|
const defs = getSettingsForTab(tabId);
|
|
308
305
|
const items: SettingItem[] = [];
|
|
309
306
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Container, type SelectItem, SelectList } from "@oh-my-pi/pi-tui";
|
|
2
|
-
import { getSelectListTheme } from "../theme/theme
|
|
3
|
-
import { DynamicBorder } from "./dynamic-border
|
|
2
|
+
import { getSelectListTheme } from "../theme/theme";
|
|
3
|
+
import { DynamicBorder } from "./dynamic-border";
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Component that renders a show images selector with borders
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Container, type SelectItem, SelectList } from "@oh-my-pi/pi-tui";
|
|
2
|
-
import { getAvailableThemes, getSelectListTheme } from "../theme/theme
|
|
3
|
-
import { DynamicBorder } from "./dynamic-border
|
|
2
|
+
import { getAvailableThemes, getSelectListTheme } from "../theme/theme";
|
|
3
|
+
import { DynamicBorder } from "./dynamic-border";
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Component that renders a theme selector
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { ThinkingLevel } from "@oh-my-pi/pi-agent-core";
|
|
2
2
|
import { Container, type SelectItem, SelectList } from "@oh-my-pi/pi-tui";
|
|
3
|
-
import { getSelectListTheme } from "../theme/theme
|
|
4
|
-
import { DynamicBorder } from "./dynamic-border
|
|
3
|
+
import { getSelectListTheme } from "../theme/theme";
|
|
4
|
+
import { DynamicBorder } from "./dynamic-border";
|
|
5
5
|
|
|
6
6
|
const LEVEL_DESCRIPTIONS: Record<ThinkingLevel, string> = {
|
|
7
7
|
off: "No reasoning",
|
|
@@ -11,14 +11,14 @@ import {
|
|
|
11
11
|
type TUI,
|
|
12
12
|
} from "@oh-my-pi/pi-tui";
|
|
13
13
|
import stripAnsi from "strip-ansi";
|
|
14
|
-
import type { CustomTool } from "../../../core/custom-tools/types
|
|
15
|
-
import { computeEditDiff, type EditDiffError, type EditDiffResult } from "../../../core/tools/edit-diff
|
|
16
|
-
import { toolRenderers } from "../../../core/tools/renderers
|
|
17
|
-
import { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, formatSize } from "../../../core/tools/truncate
|
|
18
|
-
import { sanitizeBinaryOutput } from "../../../utils/shell
|
|
19
|
-
import { getLanguageFromPath, highlightCode, theme } from "../theme/theme
|
|
20
|
-
import { renderDiff } from "./diff
|
|
21
|
-
import { truncateToVisualLines } from "./visual-truncate
|
|
14
|
+
import type { CustomTool } from "../../../core/custom-tools/types";
|
|
15
|
+
import { computeEditDiff, type EditDiffError, type EditDiffResult } from "../../../core/tools/edit-diff";
|
|
16
|
+
import { toolRenderers } from "../../../core/tools/renderers";
|
|
17
|
+
import { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, formatSize } from "../../../core/tools/truncate";
|
|
18
|
+
import { sanitizeBinaryOutput } from "../../../utils/shell";
|
|
19
|
+
import { getLanguageFromPath, highlightCode, theme } from "../theme/theme";
|
|
20
|
+
import { renderDiff } from "./diff";
|
|
21
|
+
import { truncateToVisualLines } from "./visual-truncate";
|
|
22
22
|
|
|
23
23
|
// Preview line limit for bash when not expanded
|
|
24
24
|
const BASH_PREVIEW_LINES = 5;
|
|
@@ -501,6 +501,24 @@ export class ToolExecutionComponent extends Container {
|
|
|
501
501
|
text += theme.fg("toolOutput", `\n... (${remaining} more lines, ${totalLines} total)`);
|
|
502
502
|
}
|
|
503
503
|
}
|
|
504
|
+
|
|
505
|
+
// Show LSP diagnostics if available
|
|
506
|
+
if (this.result?.details?.diagnostics?.available) {
|
|
507
|
+
const diag = this.result.details.diagnostics;
|
|
508
|
+
if (diag.diagnostics.length > 0) {
|
|
509
|
+
const icon = diag.hasErrors ? theme.fg("error", "●") : theme.fg("warning", "●");
|
|
510
|
+
text += `\n\n${icon} ${theme.fg("toolTitle", "LSP Diagnostics")} ${theme.fg("dim", `(${diag.summary})`)}`;
|
|
511
|
+
const maxDiags = this.expanded ? diag.diagnostics.length : 5;
|
|
512
|
+
const displayDiags = diag.diagnostics.slice(0, maxDiags);
|
|
513
|
+
for (const d of displayDiags) {
|
|
514
|
+
const color = d.includes("[error]") ? "error" : d.includes("[warning]") ? "warning" : "dim";
|
|
515
|
+
text += `\n ${theme.fg(color, d)}`;
|
|
516
|
+
}
|
|
517
|
+
if (diag.diagnostics.length > maxDiags) {
|
|
518
|
+
text += theme.fg("dim", `\n ... (${diag.diagnostics.length - maxDiags} more)`);
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
}
|
|
504
522
|
} else if (this.toolName === "edit") {
|
|
505
523
|
const rawPath = this.args?.file_path || this.args?.path || "";
|
|
506
524
|
const path = shortenPath(rawPath);
|
|
@@ -532,6 +550,24 @@ export class ToolExecutionComponent extends Container {
|
|
|
532
550
|
text += `\n\n${renderDiff(this.editDiffPreview.diff, { filePath: rawPath })}`;
|
|
533
551
|
}
|
|
534
552
|
}
|
|
553
|
+
|
|
554
|
+
// Show LSP diagnostics if available
|
|
555
|
+
if (this.result?.details?.diagnostics?.available) {
|
|
556
|
+
const diag = this.result.details.diagnostics;
|
|
557
|
+
if (diag.diagnostics.length > 0) {
|
|
558
|
+
const icon = diag.hasErrors ? theme.fg("error", "●") : theme.fg("warning", "●");
|
|
559
|
+
text += `\n\n${icon} ${theme.fg("toolTitle", "LSP Diagnostics")} ${theme.fg("dim", `(${diag.summary})`)}`;
|
|
560
|
+
const maxDiags = this.expanded ? diag.diagnostics.length : 5;
|
|
561
|
+
const displayDiags = diag.diagnostics.slice(0, maxDiags);
|
|
562
|
+
for (const d of displayDiags) {
|
|
563
|
+
const color = d.includes("[error]") ? "error" : d.includes("[warning]") ? "warning" : "dim";
|
|
564
|
+
text += `\n ${theme.fg(color, d)}`;
|
|
565
|
+
}
|
|
566
|
+
if (diag.diagnostics.length > maxDiags) {
|
|
567
|
+
text += theme.fg("dim", `\n ... (${diag.diagnostics.length - maxDiags} more)`);
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
}
|
|
535
571
|
} else if (this.toolName === "ls") {
|
|
536
572
|
const path = shortenPath(this.args?.path || ".");
|
|
537
573
|
const limit = this.args?.limit;
|
|
@@ -17,9 +17,9 @@ import {
|
|
|
17
17
|
TruncatedText,
|
|
18
18
|
truncateToWidth,
|
|
19
19
|
} from "@oh-my-pi/pi-tui";
|
|
20
|
-
import type { SessionTreeNode } from "../../../core/session-manager
|
|
21
|
-
import { theme } from "../theme/theme
|
|
22
|
-
import { DynamicBorder } from "./dynamic-border
|
|
20
|
+
import type { SessionTreeNode } from "../../../core/session-manager";
|
|
21
|
+
import { theme } from "../theme/theme";
|
|
22
|
+
import { DynamicBorder } from "./dynamic-border";
|
|
23
23
|
|
|
24
24
|
/** Gutter info: position (displayIndent where connector was) and whether to show │ */
|
|
25
25
|
interface GutterInfo {
|
|
@@ -356,7 +356,7 @@ class TreeList implements Component {
|
|
|
356
356
|
parts.push("branch summary", entry.summary);
|
|
357
357
|
break;
|
|
358
358
|
case "model_change":
|
|
359
|
-
parts.push("model", entry.
|
|
359
|
+
parts.push("model", entry.model);
|
|
360
360
|
break;
|
|
361
361
|
case "thinking_level_change":
|
|
362
362
|
parts.push("thinking", entry.thinkingLevel);
|
|
@@ -558,7 +558,7 @@ class TreeList implements Component {
|
|
|
558
558
|
result = theme.fg("warning", `[branch summary]: `) + normalize(entry.summary);
|
|
559
559
|
break;
|
|
560
560
|
case "model_change":
|
|
561
|
-
result = theme.fg("dim", `[model: ${entry.
|
|
561
|
+
result = theme.fg("dim", `[model: ${entry.model}]`);
|
|
562
562
|
break;
|
|
563
563
|
case "thinking_level_change":
|
|
564
564
|
result = theme.fg("dim", `[thinking: ${entry.thinkingLevel}]`);
|
|
@@ -10,8 +10,8 @@ import {
|
|
|
10
10
|
Text,
|
|
11
11
|
truncateToWidth,
|
|
12
12
|
} from "@oh-my-pi/pi-tui";
|
|
13
|
-
import { theme } from "../theme/theme
|
|
14
|
-
import { DynamicBorder } from "./dynamic-border
|
|
13
|
+
import { theme } from "../theme/theme";
|
|
14
|
+
import { DynamicBorder } from "./dynamic-border";
|
|
15
15
|
|
|
16
16
|
interface UserMessageItem {
|
|
17
17
|
id: string; // Entry ID in the session
|
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
import { type Component, visibleWidth } from "@oh-my-pi/pi-tui";
|
|
2
|
-
import { APP_NAME } from "../../../config
|
|
3
|
-
import { theme } from "../theme/theme
|
|
2
|
+
import { APP_NAME } from "../../../config";
|
|
3
|
+
import { theme } from "../theme/theme";
|
|
4
4
|
|
|
5
5
|
export interface RecentSession {
|
|
6
6
|
name: string;
|
|
7
7
|
timeAgo: string;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
+
export interface LspServerInfo {
|
|
11
|
+
name: string;
|
|
12
|
+
status: "ready" | "error" | "connecting";
|
|
13
|
+
fileTypes: string[];
|
|
14
|
+
}
|
|
15
|
+
|
|
10
16
|
/**
|
|
11
17
|
* Premium welcome screen with block-based Pi logo and two-column layout.
|
|
12
18
|
*/
|
|
@@ -15,12 +21,20 @@ export class WelcomeComponent implements Component {
|
|
|
15
21
|
private modelName: string;
|
|
16
22
|
private providerName: string;
|
|
17
23
|
private recentSessions: RecentSession[];
|
|
18
|
-
|
|
19
|
-
|
|
24
|
+
private lspServers: LspServerInfo[];
|
|
25
|
+
|
|
26
|
+
constructor(
|
|
27
|
+
version: string,
|
|
28
|
+
modelName: string,
|
|
29
|
+
providerName: string,
|
|
30
|
+
recentSessions: RecentSession[] = [],
|
|
31
|
+
lspServers: LspServerInfo[] = [],
|
|
32
|
+
) {
|
|
20
33
|
this.version = version;
|
|
21
34
|
this.modelName = modelName;
|
|
22
35
|
this.providerName = providerName;
|
|
23
36
|
this.recentSessions = recentSessions;
|
|
37
|
+
this.lspServers = lspServers;
|
|
24
38
|
}
|
|
25
39
|
|
|
26
40
|
invalidate(): void {}
|
|
@@ -34,6 +48,10 @@ export class WelcomeComponent implements Component {
|
|
|
34
48
|
this.recentSessions = sessions;
|
|
35
49
|
}
|
|
36
50
|
|
|
51
|
+
setLspServers(servers: LspServerInfo[]): void {
|
|
52
|
+
this.lspServers = servers;
|
|
53
|
+
}
|
|
54
|
+
|
|
37
55
|
render(termWidth: number): string[] {
|
|
38
56
|
// Box dimensions - responsive with min/max
|
|
39
57
|
const minWidth = 80;
|
|
@@ -76,13 +94,32 @@ export class WelcomeComponent implements Component {
|
|
|
76
94
|
}
|
|
77
95
|
}
|
|
78
96
|
|
|
97
|
+
// LSP servers content
|
|
98
|
+
const lspLines: string[] = [];
|
|
99
|
+
if (this.lspServers.length === 0) {
|
|
100
|
+
lspLines.push(` ${theme.fg("dim", "No LSP servers")}`);
|
|
101
|
+
} else {
|
|
102
|
+
for (const server of this.lspServers) {
|
|
103
|
+
const icon =
|
|
104
|
+
server.status === "ready"
|
|
105
|
+
? theme.fg("success", "●")
|
|
106
|
+
: server.status === "connecting"
|
|
107
|
+
? theme.fg("warning", "○")
|
|
108
|
+
: theme.fg("error", "●");
|
|
109
|
+
const exts = server.fileTypes.slice(0, 3).join(" ");
|
|
110
|
+
lspLines.push(` ${icon} ${theme.fg("muted", server.name)} ${theme.fg("dim", exts)}`);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
79
114
|
// Right column
|
|
80
115
|
const rightLines = [
|
|
81
116
|
` ${theme.bold(theme.fg("accent", "Tips"))}`,
|
|
82
117
|
` ${theme.fg("dim", "?")}${theme.fg("muted", " for keyboard shortcuts")}`,
|
|
83
118
|
` ${theme.fg("dim", "/")}${theme.fg("muted", " for commands")}`,
|
|
84
119
|
` ${theme.fg("dim", "!")}${theme.fg("muted", " to run bash")}`,
|
|
85
|
-
|
|
120
|
+
separator,
|
|
121
|
+
` ${theme.bold(theme.fg("accent", "LSP Servers"))}`,
|
|
122
|
+
...lspLines,
|
|
86
123
|
separator,
|
|
87
124
|
` ${theme.bold(theme.fg("accent", "Recent sessions"))}`,
|
|
88
125
|
...sessionLines,
|