@mariozechner/pi-coding-agent 0.7.29 → 0.8.2
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 +6 -0
- package/README.md +74 -4
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +7 -4
- package/dist/main.js.map +1 -1
- package/dist/settings-manager.d.ts +3 -0
- package/dist/settings-manager.d.ts.map +1 -1
- package/dist/settings-manager.js +7 -0
- package/dist/settings-manager.js.map +1 -1
- package/dist/theme/dark.json +70 -0
- package/dist/theme/light.json +69 -0
- package/dist/theme/theme-schema.json +246 -0
- package/dist/theme/theme.d.ts +33 -0
- package/dist/theme/theme.d.ts.map +1 -0
- package/dist/theme/theme.js +470 -0
- package/dist/theme/theme.js.map +1 -0
- package/dist/tui/assistant-message.d.ts.map +1 -1
- package/dist/tui/assistant-message.js +7 -7
- package/dist/tui/assistant-message.js.map +1 -1
- package/dist/tui/dynamic-border.d.ts +1 -0
- package/dist/tui/dynamic-border.d.ts.map +1 -1
- package/dist/tui/dynamic-border.js +5 -2
- package/dist/tui/dynamic-border.js.map +1 -1
- package/dist/tui/footer.d.ts +3 -1
- package/dist/tui/footer.d.ts.map +1 -1
- package/dist/tui/footer.js +20 -5
- package/dist/tui/footer.js.map +1 -1
- package/dist/tui/model-selector.d.ts.map +1 -1
- package/dist/tui/model-selector.js +14 -13
- package/dist/tui/model-selector.js.map +1 -1
- package/dist/tui/oauth-selector.d.ts.map +1 -1
- package/dist/tui/oauth-selector.js +9 -8
- package/dist/tui/oauth-selector.js.map +1 -1
- package/dist/tui/queue-mode-selector.d.ts.map +1 -1
- package/dist/tui/queue-mode-selector.js +3 -10
- package/dist/tui/queue-mode-selector.js.map +1 -1
- package/dist/tui/session-selector.d.ts +1 -0
- package/dist/tui/session-selector.d.ts.map +1 -1
- package/dist/tui/session-selector.js +11 -15
- package/dist/tui/session-selector.js.map +1 -1
- package/dist/tui/theme-selector.d.ts +11 -0
- package/dist/tui/theme-selector.d.ts.map +1 -0
- package/dist/tui/theme-selector.js +46 -0
- package/dist/tui/theme-selector.js.map +1 -0
- package/dist/tui/thinking-selector.d.ts.map +1 -1
- package/dist/tui/thinking-selector.js +3 -10
- package/dist/tui/thinking-selector.js.map +1 -1
- package/dist/tui/tool-execution.d.ts.map +1 -1
- package/dist/tui/tool-execution.js +30 -111
- package/dist/tui/tool-execution.js.map +1 -1
- package/dist/tui/tui-renderer.d.ts +3 -1
- package/dist/tui/tui-renderer.d.ts.map +1 -1
- package/dist/tui/tui-renderer.js +146 -94
- package/dist/tui/tui-renderer.js.map +1 -1
- package/dist/tui/user-message-selector.d.ts +1 -0
- package/dist/tui/user-message-selector.d.ts.map +1 -1
- package/dist/tui/user-message-selector.js +12 -20
- package/dist/tui/user-message-selector.js.map +1 -1
- package/dist/tui/user-message.d.ts +0 -1
- package/dist/tui/user-message.d.ts.map +1 -1
- package/dist/tui/user-message.js +5 -4
- package/dist/tui/user-message.js.map +1 -1
- package/package.json +6 -4
package/dist/tui/tui-renderer.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { CombinedAutocompleteProvider, Container, Input, Loader, Markdown, ProcessTerminal, Spacer, Text, TruncatedText, TUI, } from "@mariozechner/pi-tui";
|
|
2
|
-
import chalk from "chalk";
|
|
3
2
|
import { exec } from "child_process";
|
|
4
3
|
import { getChangelogPath, parseChangelog } from "../changelog.js";
|
|
5
4
|
import { exportSessionToHtml } from "../export-html.js";
|
|
6
5
|
import { getApiKeyForModel, getAvailableModels } from "../model-config.js";
|
|
7
6
|
import { listOAuthProviders, login, logout } from "../oauth/index.js";
|
|
7
|
+
import { getEditorTheme, getMarkdownTheme, onThemeChange, setTheme, theme } from "../theme/theme.js";
|
|
8
8
|
import { AssistantMessageComponent } from "./assistant-message.js";
|
|
9
9
|
import { CustomEditor } from "./custom-editor.js";
|
|
10
10
|
import { DynamicBorder } from "./dynamic-border.js";
|
|
@@ -12,6 +12,7 @@ import { FooterComponent } from "./footer.js";
|
|
|
12
12
|
import { ModelSelectorComponent } from "./model-selector.js";
|
|
13
13
|
import { OAuthSelectorComponent } from "./oauth-selector.js";
|
|
14
14
|
import { QueueModeSelectorComponent } from "./queue-mode-selector.js";
|
|
15
|
+
import { ThemeSelectorComponent } from "./theme-selector.js";
|
|
15
16
|
import { ThinkingSelectorComponent } from "./thinking-selector.js";
|
|
16
17
|
import { ToolExecutionComponent } from "./tool-execution.js";
|
|
17
18
|
import { UserMessageComponent } from "./user-message.js";
|
|
@@ -48,6 +49,8 @@ export class TuiRenderer {
|
|
|
48
49
|
thinkingSelector = null;
|
|
49
50
|
// Queue mode selector
|
|
50
51
|
queueModeSelector = null;
|
|
52
|
+
// Theme selector
|
|
53
|
+
themeSelector = null;
|
|
51
54
|
// Model selector
|
|
52
55
|
modelSelector = null;
|
|
53
56
|
// User message selector (for branching)
|
|
@@ -72,7 +75,7 @@ export class TuiRenderer {
|
|
|
72
75
|
this.chatContainer = new Container();
|
|
73
76
|
this.pendingMessagesContainer = new Container();
|
|
74
77
|
this.statusContainer = new Container();
|
|
75
|
-
this.editor = new CustomEditor();
|
|
78
|
+
this.editor = new CustomEditor(getEditorTheme());
|
|
76
79
|
this.editorContainer = new Container(); // Container to hold editor or selector
|
|
77
80
|
this.editorContainer.addChild(this.editor); // Start with editor
|
|
78
81
|
this.footer = new FooterComponent(agent.state);
|
|
@@ -113,10 +116,15 @@ export class TuiRenderer {
|
|
|
113
116
|
name: "queue",
|
|
114
117
|
description: "Select message queue mode (opens selector UI)",
|
|
115
118
|
};
|
|
119
|
+
const themeCommand = {
|
|
120
|
+
name: "theme",
|
|
121
|
+
description: "Select color theme (opens selector UI)",
|
|
122
|
+
};
|
|
116
123
|
// Setup autocomplete for file paths and slash commands
|
|
117
124
|
const autocompleteProvider = new CombinedAutocompleteProvider([
|
|
118
125
|
thinkingCommand,
|
|
119
126
|
modelCommand,
|
|
127
|
+
themeCommand,
|
|
120
128
|
exportCommand,
|
|
121
129
|
sessionCommand,
|
|
122
130
|
changelogCommand,
|
|
@@ -131,33 +139,33 @@ export class TuiRenderer {
|
|
|
131
139
|
if (this.isInitialized)
|
|
132
140
|
return;
|
|
133
141
|
// Add header with logo and instructions
|
|
134
|
-
const logo =
|
|
135
|
-
const instructions =
|
|
136
|
-
|
|
142
|
+
const logo = theme.bold(theme.fg("accent", "pi")) + theme.fg("dim", ` v${this.version}`);
|
|
143
|
+
const instructions = theme.fg("dim", "esc") +
|
|
144
|
+
theme.fg("muted", " to interrupt") +
|
|
137
145
|
"\n" +
|
|
138
|
-
|
|
139
|
-
|
|
146
|
+
theme.fg("dim", "ctrl+c") +
|
|
147
|
+
theme.fg("muted", " to clear") +
|
|
140
148
|
"\n" +
|
|
141
|
-
|
|
142
|
-
|
|
149
|
+
theme.fg("dim", "ctrl+c twice") +
|
|
150
|
+
theme.fg("muted", " to exit") +
|
|
143
151
|
"\n" +
|
|
144
|
-
|
|
145
|
-
|
|
152
|
+
theme.fg("dim", "ctrl+k") +
|
|
153
|
+
theme.fg("muted", " to delete line") +
|
|
146
154
|
"\n" +
|
|
147
|
-
|
|
148
|
-
|
|
155
|
+
theme.fg("dim", "shift+tab") +
|
|
156
|
+
theme.fg("muted", " to cycle thinking") +
|
|
149
157
|
"\n" +
|
|
150
|
-
|
|
151
|
-
|
|
158
|
+
theme.fg("dim", "ctrl+p") +
|
|
159
|
+
theme.fg("muted", " to cycle models") +
|
|
152
160
|
"\n" +
|
|
153
|
-
|
|
154
|
-
|
|
161
|
+
theme.fg("dim", "ctrl+o") +
|
|
162
|
+
theme.fg("muted", " to expand tools") +
|
|
155
163
|
"\n" +
|
|
156
|
-
|
|
157
|
-
|
|
164
|
+
theme.fg("dim", "/") +
|
|
165
|
+
theme.fg("muted", " for commands") +
|
|
158
166
|
"\n" +
|
|
159
|
-
|
|
160
|
-
|
|
167
|
+
theme.fg("dim", "drop files") +
|
|
168
|
+
theme.fg("muted", " to attach");
|
|
161
169
|
const header = new Text(logo + "\n" + instructions, 1, 0);
|
|
162
170
|
// Setup UI layout
|
|
163
171
|
this.ui.addChild(new Spacer(1));
|
|
@@ -165,21 +173,21 @@ export class TuiRenderer {
|
|
|
165
173
|
this.ui.addChild(new Spacer(1));
|
|
166
174
|
// Add new version notification if available
|
|
167
175
|
if (this.newVersion) {
|
|
168
|
-
this.ui.addChild(new DynamicBorder(
|
|
169
|
-
this.ui.addChild(new Text(
|
|
176
|
+
this.ui.addChild(new DynamicBorder((text) => theme.fg("warning", text)));
|
|
177
|
+
this.ui.addChild(new Text(theme.bold(theme.fg("warning", "Update Available")) +
|
|
170
178
|
"\n" +
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
this.ui.addChild(new DynamicBorder(
|
|
179
|
+
theme.fg("muted", `New version ${this.newVersion} is available. Run: `) +
|
|
180
|
+
theme.fg("accent", "npm install -g @mariozechner/pi-coding-agent"), 1, 0));
|
|
181
|
+
this.ui.addChild(new DynamicBorder((text) => theme.fg("warning", text)));
|
|
174
182
|
}
|
|
175
183
|
// Add changelog if provided
|
|
176
184
|
if (this.changelogMarkdown) {
|
|
177
|
-
this.ui.addChild(new DynamicBorder(
|
|
178
|
-
this.ui.addChild(new Text(
|
|
185
|
+
this.ui.addChild(new DynamicBorder());
|
|
186
|
+
this.ui.addChild(new Text(theme.bold(theme.fg("accent", "What's New")), 1, 0));
|
|
179
187
|
this.ui.addChild(new Spacer(1));
|
|
180
|
-
this.ui.addChild(new Markdown(this.changelogMarkdown.trim(), 1, 0));
|
|
188
|
+
this.ui.addChild(new Markdown(this.changelogMarkdown.trim(), 1, 0, getMarkdownTheme()));
|
|
181
189
|
this.ui.addChild(new Spacer(1));
|
|
182
|
-
this.ui.addChild(new DynamicBorder(
|
|
190
|
+
this.ui.addChild(new DynamicBorder());
|
|
183
191
|
}
|
|
184
192
|
this.ui.addChild(this.chatContainer);
|
|
185
193
|
this.ui.addChild(this.pendingMessagesContainer);
|
|
@@ -282,6 +290,12 @@ export class TuiRenderer {
|
|
|
282
290
|
this.editor.setText("");
|
|
283
291
|
return;
|
|
284
292
|
}
|
|
293
|
+
// Check for /theme command
|
|
294
|
+
if (text === "/theme") {
|
|
295
|
+
this.showThemeSelector();
|
|
296
|
+
this.editor.setText("");
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
285
299
|
// Normal message submission - validate model and API key first
|
|
286
300
|
const currentModel = this.agent.state.model;
|
|
287
301
|
if (!currentModel) {
|
|
@@ -323,6 +337,12 @@ export class TuiRenderer {
|
|
|
323
337
|
// Start the UI
|
|
324
338
|
this.ui.start();
|
|
325
339
|
this.isInitialized = true;
|
|
340
|
+
// Set up theme file watcher for live reload
|
|
341
|
+
onThemeChange(() => {
|
|
342
|
+
this.ui.invalidate();
|
|
343
|
+
this.updateEditorBorderColor();
|
|
344
|
+
this.ui.requestRender();
|
|
345
|
+
});
|
|
326
346
|
}
|
|
327
347
|
async handleEvent(event, state) {
|
|
328
348
|
if (!this.isInitialized) {
|
|
@@ -339,7 +359,7 @@ export class TuiRenderer {
|
|
|
339
359
|
this.loadingAnimation.stop();
|
|
340
360
|
}
|
|
341
361
|
this.statusContainer.clear();
|
|
342
|
-
this.loadingAnimation = new Loader(this.ui, "Working... (esc to interrupt)");
|
|
362
|
+
this.loadingAnimation = new Loader(this.ui, (spinner) => theme.fg("accent", spinner), (text) => theme.fg("muted", text), "Working... (esc to interrupt)");
|
|
343
363
|
this.statusContainer.addChild(this.loadingAnimation);
|
|
344
364
|
this.ui.requestRender();
|
|
345
365
|
break;
|
|
@@ -580,34 +600,16 @@ export class TuiRenderer {
|
|
|
580
600
|
this.lastSigintTime = now;
|
|
581
601
|
}
|
|
582
602
|
}
|
|
583
|
-
getThinkingBorderColor(level) {
|
|
584
|
-
// More thinking = more color (gray → dim colors → bright colors)
|
|
585
|
-
switch (level) {
|
|
586
|
-
case "off":
|
|
587
|
-
return chalk.gray;
|
|
588
|
-
case "minimal":
|
|
589
|
-
return chalk.dim.blue;
|
|
590
|
-
case "low":
|
|
591
|
-
return chalk.blue;
|
|
592
|
-
case "medium":
|
|
593
|
-
return chalk.cyan;
|
|
594
|
-
case "high":
|
|
595
|
-
return chalk.magenta;
|
|
596
|
-
default:
|
|
597
|
-
return chalk.gray;
|
|
598
|
-
}
|
|
599
|
-
}
|
|
600
603
|
updateEditorBorderColor() {
|
|
601
604
|
const level = this.agent.state.thinkingLevel || "off";
|
|
602
|
-
|
|
603
|
-
this.editor.borderColor = color;
|
|
605
|
+
this.editor.borderColor = theme.getThinkingBorderColor(level);
|
|
604
606
|
this.ui.requestRender();
|
|
605
607
|
}
|
|
606
608
|
cycleThinkingLevel() {
|
|
607
609
|
// Only cycle if model supports thinking
|
|
608
610
|
if (!this.agent.state.model?.reasoning) {
|
|
609
611
|
this.chatContainer.addChild(new Spacer(1));
|
|
610
|
-
this.chatContainer.addChild(new Text(
|
|
612
|
+
this.chatContainer.addChild(new Text(theme.fg("dim", "Current model does not support thinking"), 1, 0));
|
|
611
613
|
this.ui.requestRender();
|
|
612
614
|
return;
|
|
613
615
|
}
|
|
@@ -624,7 +626,7 @@ export class TuiRenderer {
|
|
|
624
626
|
this.updateEditorBorderColor();
|
|
625
627
|
// Show brief notification
|
|
626
628
|
this.chatContainer.addChild(new Spacer(1));
|
|
627
|
-
this.chatContainer.addChild(new Text(
|
|
629
|
+
this.chatContainer.addChild(new Text(theme.fg("dim", `Thinking level: ${nextLevel}`), 1, 0));
|
|
628
630
|
this.ui.requestRender();
|
|
629
631
|
}
|
|
630
632
|
async cycleModel() {
|
|
@@ -647,7 +649,7 @@ export class TuiRenderer {
|
|
|
647
649
|
}
|
|
648
650
|
if (modelsToUse.length === 1) {
|
|
649
651
|
this.chatContainer.addChild(new Spacer(1));
|
|
650
|
-
this.chatContainer.addChild(new Text(
|
|
652
|
+
this.chatContainer.addChild(new Text(theme.fg("dim", "Only one model in scope"), 1, 0));
|
|
651
653
|
this.ui.requestRender();
|
|
652
654
|
return;
|
|
653
655
|
}
|
|
@@ -669,7 +671,7 @@ export class TuiRenderer {
|
|
|
669
671
|
this.agent.setModel(nextModel);
|
|
670
672
|
// Show notification
|
|
671
673
|
this.chatContainer.addChild(new Spacer(1));
|
|
672
|
-
this.chatContainer.addChild(new Text(
|
|
674
|
+
this.chatContainer.addChild(new Text(theme.fg("dim", `Switched to ${nextModel.name || nextModel.id}`), 1, 0));
|
|
673
675
|
this.ui.requestRender();
|
|
674
676
|
}
|
|
675
677
|
toggleToolOutputExpansion() {
|
|
@@ -689,13 +691,13 @@ export class TuiRenderer {
|
|
|
689
691
|
showError(errorMessage) {
|
|
690
692
|
// Show error message in the chat
|
|
691
693
|
this.chatContainer.addChild(new Spacer(1));
|
|
692
|
-
this.chatContainer.addChild(new Text(
|
|
694
|
+
this.chatContainer.addChild(new Text(theme.fg("error", `Error: ${errorMessage}`), 1, 0));
|
|
693
695
|
this.ui.requestRender();
|
|
694
696
|
}
|
|
695
697
|
showWarning(warningMessage) {
|
|
696
698
|
// Show warning message in the chat
|
|
697
699
|
this.chatContainer.addChild(new Spacer(1));
|
|
698
|
-
this.chatContainer.addChild(new Text(
|
|
700
|
+
this.chatContainer.addChild(new Text(theme.fg("warning", `Warning: ${warningMessage}`), 1, 0));
|
|
699
701
|
this.ui.requestRender();
|
|
700
702
|
}
|
|
701
703
|
showThinkingSelector() {
|
|
@@ -709,7 +711,7 @@ export class TuiRenderer {
|
|
|
709
711
|
this.updateEditorBorderColor();
|
|
710
712
|
// Show confirmation message with proper spacing
|
|
711
713
|
this.chatContainer.addChild(new Spacer(1));
|
|
712
|
-
const confirmText = new Text(
|
|
714
|
+
const confirmText = new Text(theme.fg("dim", `Thinking level: ${level}`), 1, 0);
|
|
713
715
|
this.chatContainer.addChild(confirmText);
|
|
714
716
|
// Hide selector and show editor again
|
|
715
717
|
this.hideThinkingSelector();
|
|
@@ -741,7 +743,7 @@ export class TuiRenderer {
|
|
|
741
743
|
this.settingsManager.setQueueMode(mode);
|
|
742
744
|
// Show confirmation message with proper spacing
|
|
743
745
|
this.chatContainer.addChild(new Spacer(1));
|
|
744
|
-
const confirmText = new Text(
|
|
746
|
+
const confirmText = new Text(theme.fg("dim", `Queue mode: ${mode}`), 1, 0);
|
|
745
747
|
this.chatContainer.addChild(confirmText);
|
|
746
748
|
// Hide selector and show editor again
|
|
747
749
|
this.hideQueueModeSelector();
|
|
@@ -764,6 +766,56 @@ export class TuiRenderer {
|
|
|
764
766
|
this.queueModeSelector = null;
|
|
765
767
|
this.ui.setFocus(this.editor);
|
|
766
768
|
}
|
|
769
|
+
showThemeSelector() {
|
|
770
|
+
// Get current theme from settings
|
|
771
|
+
const currentTheme = this.settingsManager.getTheme() || "dark";
|
|
772
|
+
// Create theme selector
|
|
773
|
+
this.themeSelector = new ThemeSelectorComponent(currentTheme, (themeName) => {
|
|
774
|
+
// Apply the selected theme
|
|
775
|
+
const result = setTheme(themeName);
|
|
776
|
+
// Save theme to settings
|
|
777
|
+
this.settingsManager.setTheme(themeName);
|
|
778
|
+
// Invalidate all components to clear cached rendering
|
|
779
|
+
this.ui.invalidate();
|
|
780
|
+
// Show confirmation or error message
|
|
781
|
+
this.chatContainer.addChild(new Spacer(1));
|
|
782
|
+
if (result.success) {
|
|
783
|
+
const confirmText = new Text(theme.fg("dim", `Theme: ${themeName}`), 1, 0);
|
|
784
|
+
this.chatContainer.addChild(confirmText);
|
|
785
|
+
}
|
|
786
|
+
else {
|
|
787
|
+
const errorText = new Text(theme.fg("error", `Failed to load theme "${themeName}": ${result.error}\nFell back to dark theme.`), 1, 0);
|
|
788
|
+
this.chatContainer.addChild(errorText);
|
|
789
|
+
}
|
|
790
|
+
// Hide selector and show editor again
|
|
791
|
+
this.hideThemeSelector();
|
|
792
|
+
this.ui.requestRender();
|
|
793
|
+
}, () => {
|
|
794
|
+
// Just hide the selector
|
|
795
|
+
this.hideThemeSelector();
|
|
796
|
+
this.ui.requestRender();
|
|
797
|
+
}, (themeName) => {
|
|
798
|
+
// Preview theme on selection change
|
|
799
|
+
const result = setTheme(themeName);
|
|
800
|
+
if (result.success) {
|
|
801
|
+
this.ui.invalidate();
|
|
802
|
+
this.ui.requestRender();
|
|
803
|
+
}
|
|
804
|
+
// If failed, theme already fell back to dark, just don't re-render
|
|
805
|
+
});
|
|
806
|
+
// Replace editor with selector
|
|
807
|
+
this.editorContainer.clear();
|
|
808
|
+
this.editorContainer.addChild(this.themeSelector);
|
|
809
|
+
this.ui.setFocus(this.themeSelector.getSelectList());
|
|
810
|
+
this.ui.requestRender();
|
|
811
|
+
}
|
|
812
|
+
hideThemeSelector() {
|
|
813
|
+
// Replace selector with editor in the container
|
|
814
|
+
this.editorContainer.clear();
|
|
815
|
+
this.editorContainer.addChild(this.editor);
|
|
816
|
+
this.themeSelector = null;
|
|
817
|
+
this.ui.setFocus(this.editor);
|
|
818
|
+
}
|
|
767
819
|
showModelSelector() {
|
|
768
820
|
// Create model selector with current model
|
|
769
821
|
this.modelSelector = new ModelSelectorComponent(this.ui, this.agent.state.model, this.settingsManager, (model) => {
|
|
@@ -773,7 +825,7 @@ export class TuiRenderer {
|
|
|
773
825
|
this.sessionManager.saveModelChange(model.provider, model.id);
|
|
774
826
|
// Show confirmation message with proper spacing
|
|
775
827
|
this.chatContainer.addChild(new Spacer(1));
|
|
776
|
-
const confirmText = new Text(
|
|
828
|
+
const confirmText = new Text(theme.fg("dim", `Model: ${model.id}`), 1, 0);
|
|
777
829
|
this.chatContainer.addChild(confirmText);
|
|
778
830
|
// Hide selector and show editor again
|
|
779
831
|
this.hideModelSelector();
|
|
@@ -813,7 +865,7 @@ export class TuiRenderer {
|
|
|
813
865
|
// Don't show selector if there are no messages or only one message
|
|
814
866
|
if (userMessages.length <= 1) {
|
|
815
867
|
this.chatContainer.addChild(new Spacer(1));
|
|
816
|
-
this.chatContainer.addChild(new Text(
|
|
868
|
+
this.chatContainer.addChild(new Text(theme.fg("dim", "No messages to branch from"), 1, 0));
|
|
817
869
|
this.ui.requestRender();
|
|
818
870
|
return;
|
|
819
871
|
}
|
|
@@ -837,7 +889,7 @@ export class TuiRenderer {
|
|
|
837
889
|
this.renderInitialMessages(this.agent.state);
|
|
838
890
|
// Show confirmation message
|
|
839
891
|
this.chatContainer.addChild(new Spacer(1));
|
|
840
|
-
this.chatContainer.addChild(new Text(
|
|
892
|
+
this.chatContainer.addChild(new Text(theme.fg("dim", `Branched to new session from message ${messageIndex}`), 1, 0));
|
|
841
893
|
// Put the selected message in the editor
|
|
842
894
|
this.editor.setText(selectedText);
|
|
843
895
|
// Hide selector and show editor again
|
|
@@ -868,7 +920,7 @@ export class TuiRenderer {
|
|
|
868
920
|
const loggedInProviders = listOAuthProviders();
|
|
869
921
|
if (loggedInProviders.length === 0) {
|
|
870
922
|
this.chatContainer.addChild(new Spacer(1));
|
|
871
|
-
this.chatContainer.addChild(new Text(
|
|
923
|
+
this.chatContainer.addChild(new Text(theme.fg("dim", "No OAuth providers logged in. Use /login first."), 1, 0));
|
|
872
924
|
this.ui.requestRender();
|
|
873
925
|
return;
|
|
874
926
|
}
|
|
@@ -881,16 +933,16 @@ export class TuiRenderer {
|
|
|
881
933
|
if (mode === "login") {
|
|
882
934
|
// Handle login
|
|
883
935
|
this.chatContainer.addChild(new Spacer(1));
|
|
884
|
-
this.chatContainer.addChild(new Text(
|
|
936
|
+
this.chatContainer.addChild(new Text(theme.fg("dim", `Logging in to ${providerId}...`), 1, 0));
|
|
885
937
|
this.ui.requestRender();
|
|
886
938
|
try {
|
|
887
939
|
await login(providerId, (url) => {
|
|
888
940
|
// Show auth URL to user
|
|
889
941
|
this.chatContainer.addChild(new Spacer(1));
|
|
890
|
-
this.chatContainer.addChild(new Text(
|
|
891
|
-
this.chatContainer.addChild(new Text(
|
|
942
|
+
this.chatContainer.addChild(new Text(theme.fg("accent", "Opening browser to:"), 1, 0));
|
|
943
|
+
this.chatContainer.addChild(new Text(theme.fg("accent", url), 1, 0));
|
|
892
944
|
this.chatContainer.addChild(new Spacer(1));
|
|
893
|
-
this.chatContainer.addChild(new Text(
|
|
945
|
+
this.chatContainer.addChild(new Text(theme.fg("warning", "Paste the authorization code below:"), 1, 0));
|
|
894
946
|
this.ui.requestRender();
|
|
895
947
|
// Open URL in browser
|
|
896
948
|
const openCmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
|
|
@@ -915,8 +967,8 @@ export class TuiRenderer {
|
|
|
915
967
|
});
|
|
916
968
|
// Success
|
|
917
969
|
this.chatContainer.addChild(new Spacer(1));
|
|
918
|
-
this.chatContainer.addChild(new Text(
|
|
919
|
-
this.chatContainer.addChild(new Text(
|
|
970
|
+
this.chatContainer.addChild(new Text(theme.fg("success", `✓ Successfully logged in to ${providerId}`), 1, 0));
|
|
971
|
+
this.chatContainer.addChild(new Text(theme.fg("dim", `Tokens saved to ~/.pi/agent/oauth.json`), 1, 0));
|
|
920
972
|
this.ui.requestRender();
|
|
921
973
|
}
|
|
922
974
|
catch (error) {
|
|
@@ -928,8 +980,8 @@ export class TuiRenderer {
|
|
|
928
980
|
try {
|
|
929
981
|
await logout(providerId);
|
|
930
982
|
this.chatContainer.addChild(new Spacer(1));
|
|
931
|
-
this.chatContainer.addChild(new Text(
|
|
932
|
-
this.chatContainer.addChild(new Text(
|
|
983
|
+
this.chatContainer.addChild(new Text(theme.fg("success", `✓ Successfully logged out of ${providerId}`), 1, 0));
|
|
984
|
+
this.chatContainer.addChild(new Text(theme.fg("dim", `Credentials removed from ~/.pi/agent/oauth.json`), 1, 0));
|
|
933
985
|
this.ui.requestRender();
|
|
934
986
|
}
|
|
935
987
|
catch (error) {
|
|
@@ -963,13 +1015,13 @@ export class TuiRenderer {
|
|
|
963
1015
|
const filePath = exportSessionToHtml(this.sessionManager, this.agent.state, outputPath);
|
|
964
1016
|
// Show success message in chat - matching thinking level style
|
|
965
1017
|
this.chatContainer.addChild(new Spacer(1));
|
|
966
|
-
this.chatContainer.addChild(new Text(
|
|
1018
|
+
this.chatContainer.addChild(new Text(theme.fg("dim", `Session exported to: ${filePath}`), 1, 0));
|
|
967
1019
|
this.ui.requestRender();
|
|
968
1020
|
}
|
|
969
1021
|
catch (error) {
|
|
970
1022
|
// Show error message in chat
|
|
971
1023
|
this.chatContainer.addChild(new Spacer(1));
|
|
972
|
-
this.chatContainer.addChild(new Text(
|
|
1024
|
+
this.chatContainer.addChild(new Text(theme.fg("error", `Failed to export session: ${error.message || "Unknown error"}`), 1, 0));
|
|
973
1025
|
this.ui.requestRender();
|
|
974
1026
|
}
|
|
975
1027
|
}
|
|
@@ -1008,28 +1060,28 @@ export class TuiRenderer {
|
|
|
1008
1060
|
}
|
|
1009
1061
|
const totalTokens = totalInput + totalOutput + totalCacheRead + totalCacheWrite;
|
|
1010
1062
|
// Build info text
|
|
1011
|
-
let info = `${
|
|
1012
|
-
info += `${
|
|
1013
|
-
info += `${
|
|
1014
|
-
info += `${
|
|
1015
|
-
info += `${
|
|
1016
|
-
info += `${
|
|
1017
|
-
info += `${
|
|
1018
|
-
info += `${
|
|
1019
|
-
info += `${
|
|
1020
|
-
info += `${
|
|
1021
|
-
info += `${
|
|
1022
|
-
info += `${
|
|
1063
|
+
let info = `${theme.bold("Session Info")}\n\n`;
|
|
1064
|
+
info += `${theme.fg("dim", "File:")} ${sessionFile}\n`;
|
|
1065
|
+
info += `${theme.fg("dim", "ID:")} ${this.sessionManager.getSessionId()}\n\n`;
|
|
1066
|
+
info += `${theme.bold("Messages")}\n`;
|
|
1067
|
+
info += `${theme.fg("dim", "User:")} ${userMessages}\n`;
|
|
1068
|
+
info += `${theme.fg("dim", "Assistant:")} ${assistantMessages}\n`;
|
|
1069
|
+
info += `${theme.fg("dim", "Tool Calls:")} ${toolCalls}\n`;
|
|
1070
|
+
info += `${theme.fg("dim", "Tool Results:")} ${toolResults}\n`;
|
|
1071
|
+
info += `${theme.fg("dim", "Total:")} ${totalMessages}\n\n`;
|
|
1072
|
+
info += `${theme.bold("Tokens")}\n`;
|
|
1073
|
+
info += `${theme.fg("dim", "Input:")} ${totalInput.toLocaleString()}\n`;
|
|
1074
|
+
info += `${theme.fg("dim", "Output:")} ${totalOutput.toLocaleString()}\n`;
|
|
1023
1075
|
if (totalCacheRead > 0) {
|
|
1024
|
-
info += `${
|
|
1076
|
+
info += `${theme.fg("dim", "Cache Read:")} ${totalCacheRead.toLocaleString()}\n`;
|
|
1025
1077
|
}
|
|
1026
1078
|
if (totalCacheWrite > 0) {
|
|
1027
|
-
info += `${
|
|
1079
|
+
info += `${theme.fg("dim", "Cache Write:")} ${totalCacheWrite.toLocaleString()}\n`;
|
|
1028
1080
|
}
|
|
1029
|
-
info += `${
|
|
1081
|
+
info += `${theme.fg("dim", "Total:")} ${totalTokens.toLocaleString()}\n`;
|
|
1030
1082
|
if (totalCost > 0) {
|
|
1031
|
-
info += `\n${
|
|
1032
|
-
info += `${
|
|
1083
|
+
info += `\n${theme.bold("Cost")}\n`;
|
|
1084
|
+
info += `${theme.fg("dim", "Total:")} ${totalCost.toFixed(4)}`;
|
|
1033
1085
|
}
|
|
1034
1086
|
// Show info in chat
|
|
1035
1087
|
this.chatContainer.addChild(new Spacer(1));
|
|
@@ -1048,11 +1100,11 @@ export class TuiRenderer {
|
|
|
1048
1100
|
: "No changelog entries found.";
|
|
1049
1101
|
// Display in chat
|
|
1050
1102
|
this.chatContainer.addChild(new Spacer(1));
|
|
1051
|
-
this.chatContainer.addChild(new DynamicBorder(
|
|
1052
|
-
this.ui.addChild(new Text(
|
|
1103
|
+
this.chatContainer.addChild(new DynamicBorder());
|
|
1104
|
+
this.ui.addChild(new Text(theme.bold(theme.fg("accent", "What's New")), 1, 0));
|
|
1053
1105
|
this.ui.addChild(new Spacer(1));
|
|
1054
|
-
this.chatContainer.addChild(new Markdown(changelogMarkdown, 1, 1));
|
|
1055
|
-
this.chatContainer.addChild(new DynamicBorder(
|
|
1106
|
+
this.chatContainer.addChild(new Markdown(changelogMarkdown, 1, 1, getMarkdownTheme()));
|
|
1107
|
+
this.chatContainer.addChild(new DynamicBorder());
|
|
1056
1108
|
this.ui.requestRender();
|
|
1057
1109
|
}
|
|
1058
1110
|
updatePendingMessagesDisplay() {
|
|
@@ -1060,7 +1112,7 @@ export class TuiRenderer {
|
|
|
1060
1112
|
if (this.queuedMessages.length > 0) {
|
|
1061
1113
|
this.pendingMessagesContainer.addChild(new Spacer(1));
|
|
1062
1114
|
for (const message of this.queuedMessages) {
|
|
1063
|
-
const queuedText =
|
|
1115
|
+
const queuedText = theme.fg("dim", "Queued: " + message);
|
|
1064
1116
|
this.pendingMessagesContainer.addChild(new TruncatedText(queuedText, 1, 0));
|
|
1065
1117
|
}
|
|
1066
1118
|
}
|