@mariozechner/pi-coding-agent 0.29.0 → 0.30.0
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 +24 -0
- package/README.md +30 -13
- package/dist/cli/args.d.ts +1 -0
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +4 -0
- package/dist/cli/args.js.map +1 -1
- package/dist/core/agent-session.d.ts +3 -2
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +11 -8
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/custom-tools/loader.d.ts +5 -0
- package/dist/core/custom-tools/loader.d.ts.map +1 -1
- package/dist/core/custom-tools/loader.js +58 -3
- package/dist/core/custom-tools/loader.js.map +1 -1
- package/dist/core/hooks/loader.d.ts.map +1 -1
- package/dist/core/hooks/loader.js +8 -1
- package/dist/core/hooks/loader.js.map +1 -1
- package/dist/core/session-manager.d.ts +26 -9
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +75 -37
- package/dist/core/session-manager.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +26 -5
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/custom-editor.d.ts +2 -0
- package/dist/modes/interactive/components/custom-editor.d.ts.map +1 -1
- package/dist/modes/interactive/components/custom-editor.js +13 -1
- package/dist/modes/interactive/components/custom-editor.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts +33 -0
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -0
- package/dist/modes/interactive/components/settings-selector.js +164 -0
- package/dist/modes/interactive/components/settings-selector.js.map +1 -0
- package/dist/modes/interactive/interactive-mode.d.ts +1 -5
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +80 -121
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/theme/theme.d.ts +1 -0
- package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme.js +9 -0
- package/dist/modes/interactive/theme/theme.js.map +1 -1
- package/docs/sdk.md +6 -3
- package/examples/sdk/11-sessions.ts +5 -3
- package/package.json +4 -4
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import * as fs from "node:fs";
|
|
6
6
|
import * as os from "node:os";
|
|
7
7
|
import * as path from "node:path";
|
|
8
|
-
import { CombinedAutocompleteProvider, Container,
|
|
8
|
+
import { CombinedAutocompleteProvider, Container, Input, Loader, Markdown, ProcessTerminal, Spacer, Text, TruncatedText, TUI, visibleWidth, } from "@mariozechner/pi-tui";
|
|
9
9
|
import { exec, spawnSync } from "child_process";
|
|
10
10
|
import { APP_NAME, getAuthPath, getDebugLogPath } from "../../config.js";
|
|
11
11
|
import { isBashExecutionMessage } from "../../core/messages.js";
|
|
@@ -25,15 +25,12 @@ import { HookInputComponent } from "./components/hook-input.js";
|
|
|
25
25
|
import { HookSelectorComponent } from "./components/hook-selector.js";
|
|
26
26
|
import { ModelSelectorComponent } from "./components/model-selector.js";
|
|
27
27
|
import { OAuthSelectorComponent } from "./components/oauth-selector.js";
|
|
28
|
-
import { QueueModeSelectorComponent } from "./components/queue-mode-selector.js";
|
|
29
28
|
import { SessionSelectorComponent } from "./components/session-selector.js";
|
|
30
|
-
import {
|
|
31
|
-
import { ThemeSelectorComponent } from "./components/theme-selector.js";
|
|
32
|
-
import { ThinkingSelectorComponent } from "./components/thinking-selector.js";
|
|
29
|
+
import { SettingsSelectorComponent } from "./components/settings-selector.js";
|
|
33
30
|
import { ToolExecutionComponent } from "./components/tool-execution.js";
|
|
34
31
|
import { UserMessageComponent } from "./components/user-message.js";
|
|
35
32
|
import { UserMessageSelectorComponent } from "./components/user-message-selector.js";
|
|
36
|
-
import { getEditorTheme, getMarkdownTheme, onThemeChange, setTheme, theme } from "./theme/theme.js";
|
|
33
|
+
import { getAvailableThemes, getEditorTheme, getMarkdownTheme, onThemeChange, setTheme, theme } from "./theme/theme.js";
|
|
37
34
|
export class InteractiveMode {
|
|
38
35
|
setToolUIContext;
|
|
39
36
|
session;
|
|
@@ -107,7 +104,7 @@ export class InteractiveMode {
|
|
|
107
104
|
this.footer.setAutoCompactEnabled(session.autoCompactionEnabled);
|
|
108
105
|
// Define slash commands for autocomplete
|
|
109
106
|
const slashCommands = [
|
|
110
|
-
{ name: "
|
|
107
|
+
{ name: "settings", description: "Open settings menu" },
|
|
111
108
|
{ name: "model", description: "Select model (opens selector UI)" },
|
|
112
109
|
{ name: "export", description: "Export session to HTML file" },
|
|
113
110
|
{ name: "copy", description: "Copy last agent message to clipboard" },
|
|
@@ -117,17 +114,10 @@ export class InteractiveMode {
|
|
|
117
114
|
{ name: "branch", description: "Create a new branch from a previous message" },
|
|
118
115
|
{ name: "login", description: "Login with OAuth provider" },
|
|
119
116
|
{ name: "logout", description: "Logout from OAuth provider" },
|
|
120
|
-
{ name: "queue", description: "Select message queue mode (opens selector UI)" },
|
|
121
|
-
{ name: "theme", description: "Select color theme (opens selector UI)" },
|
|
122
117
|
{ name: "new", description: "Start a new session" },
|
|
123
118
|
{ name: "compact", description: "Manually compact the session context" },
|
|
124
|
-
{ name: "autocompact", description: "Toggle automatic context compaction" },
|
|
125
119
|
{ name: "resume", description: "Resume a different session" },
|
|
126
120
|
];
|
|
127
|
-
// Add image toggle command only if terminal supports images
|
|
128
|
-
if (getCapabilities().images) {
|
|
129
|
-
slashCommands.push({ name: "show-images", description: "Toggle inline image display" });
|
|
130
|
-
}
|
|
131
121
|
// Load hide thinking block setting
|
|
132
122
|
this.hideThinkingBlock = this.settingsManager.getHideThinkingBlock();
|
|
133
123
|
// Convert file commands to SlashCommand format
|
|
@@ -165,9 +155,12 @@ export class InteractiveMode {
|
|
|
165
155
|
theme.fg("dim", "shift+tab") +
|
|
166
156
|
theme.fg("muted", " to cycle thinking") +
|
|
167
157
|
"\n" +
|
|
168
|
-
theme.fg("dim", "ctrl+p") +
|
|
158
|
+
theme.fg("dim", "ctrl+p/shift+ctrl+p") +
|
|
169
159
|
theme.fg("muted", " to cycle models") +
|
|
170
160
|
"\n" +
|
|
161
|
+
theme.fg("dim", "ctrl+l") +
|
|
162
|
+
theme.fg("muted", " to select model") +
|
|
163
|
+
"\n" +
|
|
171
164
|
theme.fg("dim", "ctrl+o") +
|
|
172
165
|
theme.fg("muted", " to expand tools") +
|
|
173
166
|
"\n" +
|
|
@@ -492,7 +485,9 @@ export class InteractiveMode {
|
|
|
492
485
|
this.editor.onCtrlD = () => this.handleCtrlD();
|
|
493
486
|
this.editor.onCtrlZ = () => this.handleCtrlZ();
|
|
494
487
|
this.editor.onShiftTab = () => this.cycleThinkingLevel();
|
|
495
|
-
this.editor.onCtrlP = () => this.cycleModel();
|
|
488
|
+
this.editor.onCtrlP = () => this.cycleModel("forward");
|
|
489
|
+
this.editor.onShiftCtrlP = () => this.cycleModel("backward");
|
|
490
|
+
this.editor.onCtrlL = () => this.showModelSelector();
|
|
496
491
|
this.editor.onCtrlO = () => this.toggleToolOutputExpansion();
|
|
497
492
|
this.editor.onCtrlT = () => this.toggleThinkingBlockVisibility();
|
|
498
493
|
this.editor.onCtrlG = () => this.openExternalEditor();
|
|
@@ -510,8 +505,8 @@ export class InteractiveMode {
|
|
|
510
505
|
if (!text)
|
|
511
506
|
return;
|
|
512
507
|
// Handle slash commands
|
|
513
|
-
if (text === "/
|
|
514
|
-
this.
|
|
508
|
+
if (text === "/settings") {
|
|
509
|
+
this.showSettingsSelector();
|
|
515
510
|
this.editor.setText("");
|
|
516
511
|
return;
|
|
517
512
|
}
|
|
@@ -560,16 +555,6 @@ export class InteractiveMode {
|
|
|
560
555
|
this.editor.setText("");
|
|
561
556
|
return;
|
|
562
557
|
}
|
|
563
|
-
if (text === "/queue") {
|
|
564
|
-
this.showQueueModeSelector();
|
|
565
|
-
this.editor.setText("");
|
|
566
|
-
return;
|
|
567
|
-
}
|
|
568
|
-
if (text === "/theme") {
|
|
569
|
-
this.showThemeSelector();
|
|
570
|
-
this.editor.setText("");
|
|
571
|
-
return;
|
|
572
|
-
}
|
|
573
558
|
if (text === "/new") {
|
|
574
559
|
this.editor.setText("");
|
|
575
560
|
await this.handleClearCommand();
|
|
@@ -587,16 +572,6 @@ export class InteractiveMode {
|
|
|
587
572
|
}
|
|
588
573
|
return;
|
|
589
574
|
}
|
|
590
|
-
if (text === "/autocompact") {
|
|
591
|
-
this.handleAutocompactCommand();
|
|
592
|
-
this.editor.setText("");
|
|
593
|
-
return;
|
|
594
|
-
}
|
|
595
|
-
if (text === "/show-images") {
|
|
596
|
-
this.showShowImagesSelector();
|
|
597
|
-
this.editor.setText("");
|
|
598
|
-
return;
|
|
599
|
-
}
|
|
600
575
|
if (text === "/debug") {
|
|
601
576
|
this.handleDebugCommand();
|
|
602
577
|
this.editor.setText("");
|
|
@@ -1052,9 +1027,9 @@ export class InteractiveMode {
|
|
|
1052
1027
|
this.showStatus(`Thinking level: ${newLevel}`);
|
|
1053
1028
|
}
|
|
1054
1029
|
}
|
|
1055
|
-
async cycleModel() {
|
|
1030
|
+
async cycleModel(direction) {
|
|
1056
1031
|
try {
|
|
1057
|
-
const result = await this.session.cycleModel();
|
|
1032
|
+
const result = await this.session.cycleModel(direction);
|
|
1058
1033
|
if (result === null) {
|
|
1059
1034
|
const msg = this.session.scopedModels.length > 0 ? "Only one model in scope" : "Only one model available";
|
|
1060
1035
|
this.showStatus(msg);
|
|
@@ -1202,59 +1177,74 @@ export class InteractiveMode {
|
|
|
1202
1177
|
this.ui.setFocus(focus);
|
|
1203
1178
|
this.ui.requestRender();
|
|
1204
1179
|
}
|
|
1205
|
-
|
|
1180
|
+
showSettingsSelector() {
|
|
1206
1181
|
this.showSelector((done) => {
|
|
1207
|
-
const selector = new
|
|
1208
|
-
this.session.
|
|
1209
|
-
this.
|
|
1210
|
-
this.
|
|
1211
|
-
|
|
1212
|
-
this.
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
this.
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
if (result.success) {
|
|
1242
|
-
this.showStatus(`Theme: ${themeName}`);
|
|
1243
|
-
}
|
|
1244
|
-
else {
|
|
1245
|
-
this.showError(`Failed to load theme "${themeName}": ${result.error}\nFell back to dark theme.`);
|
|
1246
|
-
}
|
|
1247
|
-
}, () => {
|
|
1248
|
-
done();
|
|
1249
|
-
this.ui.requestRender();
|
|
1250
|
-
}, (themeName) => {
|
|
1251
|
-
const result = setTheme(themeName, true);
|
|
1252
|
-
if (result.success) {
|
|
1182
|
+
const selector = new SettingsSelectorComponent({
|
|
1183
|
+
autoCompact: this.session.autoCompactionEnabled,
|
|
1184
|
+
showImages: this.settingsManager.getShowImages(),
|
|
1185
|
+
queueMode: this.session.queueMode,
|
|
1186
|
+
thinkingLevel: this.session.thinkingLevel,
|
|
1187
|
+
availableThinkingLevels: this.session.getAvailableThinkingLevels(),
|
|
1188
|
+
currentTheme: this.settingsManager.getTheme() || "dark",
|
|
1189
|
+
availableThemes: getAvailableThemes(),
|
|
1190
|
+
hideThinkingBlock: this.hideThinkingBlock,
|
|
1191
|
+
collapseChangelog: this.settingsManager.getCollapseChangelog(),
|
|
1192
|
+
}, {
|
|
1193
|
+
onAutoCompactChange: (enabled) => {
|
|
1194
|
+
this.session.setAutoCompactionEnabled(enabled);
|
|
1195
|
+
this.footer.setAutoCompactEnabled(enabled);
|
|
1196
|
+
},
|
|
1197
|
+
onShowImagesChange: (enabled) => {
|
|
1198
|
+
this.settingsManager.setShowImages(enabled);
|
|
1199
|
+
for (const child of this.chatContainer.children) {
|
|
1200
|
+
if (child instanceof ToolExecutionComponent) {
|
|
1201
|
+
child.setShowImages(enabled);
|
|
1202
|
+
}
|
|
1203
|
+
}
|
|
1204
|
+
},
|
|
1205
|
+
onQueueModeChange: (mode) => {
|
|
1206
|
+
this.session.setQueueMode(mode);
|
|
1207
|
+
},
|
|
1208
|
+
onThinkingLevelChange: (level) => {
|
|
1209
|
+
this.session.setThinkingLevel(level);
|
|
1210
|
+
this.footer.updateState(this.session.state);
|
|
1211
|
+
this.updateEditorBorderColor();
|
|
1212
|
+
},
|
|
1213
|
+
onThemeChange: (themeName) => {
|
|
1214
|
+
const result = setTheme(themeName, true);
|
|
1215
|
+
this.settingsManager.setTheme(themeName);
|
|
1253
1216
|
this.ui.invalidate();
|
|
1217
|
+
if (!result.success) {
|
|
1218
|
+
this.showError(`Failed to load theme "${themeName}": ${result.error}\nFell back to dark theme.`);
|
|
1219
|
+
}
|
|
1220
|
+
},
|
|
1221
|
+
onThemePreview: (themeName) => {
|
|
1222
|
+
const result = setTheme(themeName, true);
|
|
1223
|
+
if (result.success) {
|
|
1224
|
+
this.ui.invalidate();
|
|
1225
|
+
this.ui.requestRender();
|
|
1226
|
+
}
|
|
1227
|
+
},
|
|
1228
|
+
onHideThinkingBlockChange: (hidden) => {
|
|
1229
|
+
this.hideThinkingBlock = hidden;
|
|
1230
|
+
this.settingsManager.setHideThinkingBlock(hidden);
|
|
1231
|
+
for (const child of this.chatContainer.children) {
|
|
1232
|
+
if (child instanceof AssistantMessageComponent) {
|
|
1233
|
+
child.setHideThinkingBlock(hidden);
|
|
1234
|
+
}
|
|
1235
|
+
}
|
|
1236
|
+
this.chatContainer.clear();
|
|
1237
|
+
this.rebuildChatFromMessages();
|
|
1238
|
+
},
|
|
1239
|
+
onCollapseChangelogChange: (collapsed) => {
|
|
1240
|
+
this.settingsManager.setCollapseChangelog(collapsed);
|
|
1241
|
+
},
|
|
1242
|
+
onCancel: () => {
|
|
1243
|
+
done();
|
|
1254
1244
|
this.ui.requestRender();
|
|
1255
|
-
}
|
|
1245
|
+
},
|
|
1256
1246
|
});
|
|
1257
|
-
return { component: selector, focus: selector.
|
|
1247
|
+
return { component: selector, focus: selector.getSettingsList() };
|
|
1258
1248
|
});
|
|
1259
1249
|
}
|
|
1260
1250
|
showModelSelector() {
|
|
@@ -1308,7 +1298,7 @@ export class InteractiveMode {
|
|
|
1308
1298
|
}
|
|
1309
1299
|
showSessionSelector() {
|
|
1310
1300
|
this.showSelector((done) => {
|
|
1311
|
-
const sessions = SessionManager.list(this.sessionManager.getCwd());
|
|
1301
|
+
const sessions = SessionManager.list(this.sessionManager.getCwd(), this.sessionManager.getSessionDir());
|
|
1312
1302
|
const selector = new SessionSelectorComponent(sessions, async (sessionPath) => {
|
|
1313
1303
|
done();
|
|
1314
1304
|
await this.handleResumeSession(sessionPath);
|
|
@@ -1640,37 +1630,6 @@ export class InteractiveMode {
|
|
|
1640
1630
|
}
|
|
1641
1631
|
await this.executeCompaction(customInstructions, false);
|
|
1642
1632
|
}
|
|
1643
|
-
handleAutocompactCommand() {
|
|
1644
|
-
const newState = !this.session.autoCompactionEnabled;
|
|
1645
|
-
this.session.setAutoCompactionEnabled(newState);
|
|
1646
|
-
this.footer.setAutoCompactEnabled(newState);
|
|
1647
|
-
this.showStatus(`Auto-compaction: ${newState ? "on" : "off"}`);
|
|
1648
|
-
}
|
|
1649
|
-
showShowImagesSelector() {
|
|
1650
|
-
// Only available if terminal supports images
|
|
1651
|
-
const caps = getCapabilities();
|
|
1652
|
-
if (!caps.images) {
|
|
1653
|
-
this.showWarning("Your terminal does not support inline images");
|
|
1654
|
-
return;
|
|
1655
|
-
}
|
|
1656
|
-
this.showSelector((done) => {
|
|
1657
|
-
const selector = new ShowImagesSelectorComponent(this.settingsManager.getShowImages(), (newValue) => {
|
|
1658
|
-
this.settingsManager.setShowImages(newValue);
|
|
1659
|
-
// Update all existing tool execution components with new setting
|
|
1660
|
-
for (const child of this.chatContainer.children) {
|
|
1661
|
-
if (child instanceof ToolExecutionComponent) {
|
|
1662
|
-
child.setShowImages(newValue);
|
|
1663
|
-
}
|
|
1664
|
-
}
|
|
1665
|
-
done();
|
|
1666
|
-
this.showStatus(`Inline images: ${newValue ? "on" : "off"}`);
|
|
1667
|
-
}, () => {
|
|
1668
|
-
done();
|
|
1669
|
-
this.ui.requestRender();
|
|
1670
|
-
});
|
|
1671
|
-
return { component: selector, focus: selector.getSelectList() };
|
|
1672
|
-
});
|
|
1673
|
-
}
|
|
1674
1633
|
async executeCompaction(customInstructions, isAuto = false) {
|
|
1675
1634
|
// Stop loading animation
|
|
1676
1635
|
if (this.loadingAnimation) {
|