@earendil-works/pi-coding-agent 0.80.2 → 0.80.3
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 +48 -1
- package/README.md +2 -1
- package/dist/cli/file-processor.d.ts.map +1 -1
- package/dist/cli/file-processor.js +13 -25
- package/dist/cli/file-processor.js.map +1 -1
- package/dist/core/agent-session.d.ts +2 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +38 -28
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/extensions/index.d.ts +1 -1
- package/dist/core/extensions/index.d.ts.map +1 -1
- package/dist/core/extensions/index.js.map +1 -1
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +4 -0
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/types.d.ts +8 -1
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/http-dispatcher.d.ts.map +1 -1
- package/dist/core/http-dispatcher.js +28 -1
- package/dist/core/http-dispatcher.js.map +1 -1
- package/dist/core/model-resolver.d.ts.map +1 -1
- package/dist/core/model-resolver.js +1 -1
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +2 -0
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/session-manager.d.ts +1 -1
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +7 -4
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/settings-manager.d.ts +5 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +19 -0
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/timings.d.ts +4 -2
- package/dist/core/timings.d.ts.map +1 -1
- package/dist/core/timings.js +24 -14
- package/dist/core/timings.js.map +1 -1
- package/dist/core/tools/read.d.ts.map +1 -1
- package/dist/core/tools/read.js +12 -25
- package/dist/core/tools/read.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +16 -4
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/assistant-message.d.ts +3 -1
- package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/assistant-message.js +23 -15
- package/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/dist/modes/interactive/components/extension-editor.d.ts +3 -1
- package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
- package/dist/modes/interactive/components/extension-editor.js +12 -3
- package/dist/modes/interactive/components/extension-editor.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts +2 -0
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +13 -1
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/components/status-indicator.d.ts +28 -0
- package/dist/modes/interactive/components/status-indicator.d.ts.map +1 -0
- package/dist/modes/interactive/components/status-indicator.js +60 -0
- package/dist/modes/interactive/components/status-indicator.js.map +1 -0
- package/dist/modes/interactive/components/user-message.d.ts +6 -2
- package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/user-message.js +19 -6
- package/dist/modes/interactive/components/user-message.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +6 -7
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +115 -135
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-client.d.ts +15 -0
- package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-client.js +14 -0
- package/dist/modes/rpc/rpc-client.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +16 -0
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts +26 -0
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-types.js.map +1 -1
- package/dist/rpc-entry.d.ts +3 -0
- package/dist/rpc-entry.d.ts.map +1 -0
- package/dist/rpc-entry.js +10 -0
- package/dist/rpc-entry.js.map +1 -0
- package/dist/utils/image-convert.d.ts +1 -0
- package/dist/utils/image-convert.d.ts.map +1 -1
- package/dist/utils/image-convert.js +21 -15
- package/dist/utils/image-convert.js.map +1 -1
- package/dist/utils/image-process.d.ts +18 -0
- package/dist/utils/image-process.d.ts.map +1 -0
- package/dist/utils/image-process.js +83 -0
- package/dist/utils/image-process.js.map +1 -0
- package/dist/utils/mime.d.ts.map +1 -1
- package/dist/utils/mime.js +41 -0
- package/dist/utils/mime.js.map +1 -1
- package/docs/extensions.md +14 -0
- package/docs/keybindings.md +1 -1
- package/docs/providers.md +2 -1
- package/docs/rpc.md +58 -0
- package/docs/settings.md +10 -0
- package/docs/usage.md +2 -2
- package/examples/extensions/custom-compaction.ts +1 -0
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/gondolin/package-lock.json +2 -2
- package/examples/extensions/gondolin/package.json +1 -1
- package/examples/extensions/handoff.ts +1 -1
- package/examples/extensions/qna.ts +1 -1
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/summarize.ts +1 -0
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/npm-shrinkwrap.json +12 -12
- package/package.json +8 -5
|
@@ -7,7 +7,7 @@ import * as fs from "node:fs";
|
|
|
7
7
|
import * as os from "node:os";
|
|
8
8
|
import * as path from "node:path";
|
|
9
9
|
import { getProviders, } from "@earendil-works/pi-ai/compat";
|
|
10
|
-
import { CombinedAutocompleteProvider, Container, fuzzyFilter, getCapabilities, hyperlink,
|
|
10
|
+
import { CombinedAutocompleteProvider, Container, fuzzyFilter, getCapabilities, hyperlink, Markdown, matchesKey, ProcessTerminal, Spacer, setKeybindings, Text, TruncatedText, TUI, visibleWidth, } from "@earendil-works/pi-tui";
|
|
11
11
|
import chalk from "chalk";
|
|
12
12
|
import { spawn, spawnSync } from "child_process";
|
|
13
13
|
import { APP_NAME, APP_TITLE, CONFIG_DIR_NAME, getAgentDir, getAuthPath, getDebugLogPath, getDocsPath, getShareViewerUrl, VERSION, } from "../../config.js";
|
|
@@ -40,7 +40,6 @@ import { BashExecutionComponent } from "./components/bash-execution.js";
|
|
|
40
40
|
import { BorderedLoader } from "./components/bordered-loader.js";
|
|
41
41
|
import { BranchSummaryMessageComponent } from "./components/branch-summary-message.js";
|
|
42
42
|
import { CompactionSummaryMessageComponent } from "./components/compaction-summary-message.js";
|
|
43
|
-
import { CountdownTimer } from "./components/countdown-timer.js";
|
|
44
43
|
import { CustomEditor } from "./components/custom-editor.js";
|
|
45
44
|
import { CustomMessageComponent } from "./components/custom-message.js";
|
|
46
45
|
import { DaxnutsComponent } from "./components/daxnuts.js";
|
|
@@ -58,6 +57,7 @@ import { ScopedModelsSelectorComponent } from "./components/scoped-models-select
|
|
|
58
57
|
import { SessionSelectorComponent } from "./components/session-selector.js";
|
|
59
58
|
import { SettingsSelectorComponent } from "./components/settings-selector.js";
|
|
60
59
|
import { SkillInvocationMessageComponent } from "./components/skill-invocation-message.js";
|
|
60
|
+
import { BranchSummaryStatusIndicator, CompactionStatusIndicator, IdleStatus, RetryStatusIndicator, WorkingStatusIndicator, } from "./components/status-indicator.js";
|
|
61
61
|
import { ToolExecutionComponent } from "./components/tool-execution.js";
|
|
62
62
|
import { TreeSelectorComponent } from "./components/tree-selector.js";
|
|
63
63
|
import { TrustSelectorComponent } from "./components/trust-selector.js";
|
|
@@ -134,6 +134,7 @@ export function isApiKeyLoginProvider(providerId, oauthProviderIds, builtInProvi
|
|
|
134
134
|
export class InteractiveMode {
|
|
135
135
|
runtimeHost;
|
|
136
136
|
ui;
|
|
137
|
+
loadedResourcesContainer;
|
|
137
138
|
chatContainer;
|
|
138
139
|
pendingMessagesContainer;
|
|
139
140
|
statusContainer;
|
|
@@ -152,7 +153,8 @@ export class InteractiveMode {
|
|
|
152
153
|
isInitialized = false;
|
|
153
154
|
onInputCallback;
|
|
154
155
|
pendingUserInputs = [];
|
|
155
|
-
|
|
156
|
+
activeStatusIndicator = undefined;
|
|
157
|
+
idleStatus = new IdleStatus();
|
|
156
158
|
workingMessage = undefined;
|
|
157
159
|
workingVisible = true;
|
|
158
160
|
workingIndicatorOptions = undefined;
|
|
@@ -176,6 +178,7 @@ export class InteractiveMode {
|
|
|
176
178
|
toolOutputExpanded = false;
|
|
177
179
|
// Thinking block visibility state
|
|
178
180
|
hideThinkingBlock = false;
|
|
181
|
+
outputPad = 1;
|
|
179
182
|
// Skill commands: command name -> skill file path
|
|
180
183
|
skillCommands = new Map();
|
|
181
184
|
// Agent subscription unsubscribe function
|
|
@@ -188,11 +191,8 @@ export class InteractiveMode {
|
|
|
188
191
|
// Track pending bash components (shown in pending area, moved to chat on submit)
|
|
189
192
|
pendingBashComponents = [];
|
|
190
193
|
// Auto-compaction state
|
|
191
|
-
autoCompactionLoader = undefined;
|
|
192
194
|
autoCompactionEscapeHandler;
|
|
193
195
|
// Auto-retry state
|
|
194
|
-
retryLoader = undefined;
|
|
195
|
-
retryCountdown = undefined;
|
|
196
196
|
retryEscapeHandler;
|
|
197
197
|
// Messages queued while compaction is running
|
|
198
198
|
compactionQueuedMessages = [];
|
|
@@ -246,6 +246,7 @@ export class InteractiveMode {
|
|
|
246
246
|
this.ui = new TUI(new ProcessTerminal(), this.settingsManager.getShowHardwareCursor());
|
|
247
247
|
this.ui.setClearOnShrink(this.settingsManager.getClearOnShrink());
|
|
248
248
|
this.headerContainer = new Container();
|
|
249
|
+
this.loadedResourcesContainer = new Container();
|
|
249
250
|
this.chatContainer = new Container();
|
|
250
251
|
this.pendingMessagesContainer = new Container();
|
|
251
252
|
this.statusContainer = new Container();
|
|
@@ -267,6 +268,7 @@ export class InteractiveMode {
|
|
|
267
268
|
this.footer.setAutoCompactEnabled(this.session.autoCompactionEnabled);
|
|
268
269
|
// Load hide thinking block setting
|
|
269
270
|
this.hideThinkingBlock = this.settingsManager.getHideThinkingBlock();
|
|
271
|
+
this.outputPad = this.settingsManager.getOutputPad();
|
|
270
272
|
// Register themes from resource loader and initialize
|
|
271
273
|
setRegisteredThemes(this.session.resourceLoader.getThemes().themes);
|
|
272
274
|
this.themeController = new InteractiveThemeController(this.ui, this.settingsManager, (message) => this.showError(message), () => this.updateEditorBorderColor());
|
|
@@ -439,8 +441,10 @@ export class InteractiveMode {
|
|
|
439
441
|
: "";
|
|
440
442
|
console.log(theme.fg("dim", `Model scope: ${modelList}${cycleHint}`));
|
|
441
443
|
}
|
|
442
|
-
// Add header container as first child. Populate it after
|
|
444
|
+
// Add header container as first child. Populate it after applying theme settings.
|
|
445
|
+
// Keep loaded resources before chat so restored session messages never precede them.
|
|
443
446
|
this.ui.addChild(this.headerContainer);
|
|
447
|
+
this.ui.addChild(this.loadedResourcesContainer);
|
|
444
448
|
this.ui.addChild(this.chatContainer);
|
|
445
449
|
this.ui.addChild(this.pendingMessagesContainer);
|
|
446
450
|
this.ui.addChild(this.statusContainer);
|
|
@@ -990,6 +994,8 @@ export class InteractiveMode {
|
|
|
990
994
|
return lines.join("\n");
|
|
991
995
|
}
|
|
992
996
|
showLoadedResources(options) {
|
|
997
|
+
// Resource rendering is idempotent; chat clears no longer clear this separate container.
|
|
998
|
+
this.loadedResourcesContainer.clear();
|
|
993
999
|
const showListing = options?.force || this.options.verbose || !this.settingsManager.getQuietStartup();
|
|
994
1000
|
const showDiagnostics = showListing || options?.showDiagnosticsWhenQuiet === true;
|
|
995
1001
|
if (!showListing && !showDiagnostics) {
|
|
@@ -1005,8 +1011,8 @@ export class InteractiveMode {
|
|
|
1005
1011
|
};
|
|
1006
1012
|
const addLoadedSection = (name, collapsedBody, expandedBody = collapsedBody, color = "mdHeading") => {
|
|
1007
1013
|
const section = new ExpandableText(() => `${sectionHeader(name, color)}\n${collapsedBody}`, () => `${sectionHeader(name, color)}\n${expandedBody}`, this.getStartupExpansionState(), 0, 0);
|
|
1008
|
-
this.
|
|
1009
|
-
this.
|
|
1014
|
+
this.loadedResourcesContainer.addChild(section);
|
|
1015
|
+
this.loadedResourcesContainer.addChild(new Spacer(1));
|
|
1010
1016
|
};
|
|
1011
1017
|
const skillsResult = this.session.resourceLoader.getSkills();
|
|
1012
1018
|
const promptsResult = this.session.resourceLoader.getPrompts();
|
|
@@ -1040,7 +1046,7 @@ export class InteractiveMode {
|
|
|
1040
1046
|
if (showListing) {
|
|
1041
1047
|
const contextFiles = this.session.resourceLoader.getAgentsFiles().agentsFiles;
|
|
1042
1048
|
if (contextFiles.length > 0) {
|
|
1043
|
-
this.
|
|
1049
|
+
this.loadedResourcesContainer.addChild(new Spacer(1));
|
|
1044
1050
|
const contextList = contextFiles
|
|
1045
1051
|
.map((f) => theme.fg("dim", ` ${this.formatDisplayPath(f.path)}`))
|
|
1046
1052
|
.join("\n");
|
|
@@ -1103,14 +1109,14 @@ export class InteractiveMode {
|
|
|
1103
1109
|
const skillDiagnostics = skillsResult.diagnostics;
|
|
1104
1110
|
if (skillDiagnostics.length > 0) {
|
|
1105
1111
|
const warningLines = this.formatDiagnostics(skillDiagnostics, sourceInfos);
|
|
1106
|
-
this.
|
|
1107
|
-
this.
|
|
1112
|
+
this.loadedResourcesContainer.addChild(new Text(`${theme.fg("warning", "[Skill conflicts]")}\n${warningLines}`, 0, 0));
|
|
1113
|
+
this.loadedResourcesContainer.addChild(new Spacer(1));
|
|
1108
1114
|
}
|
|
1109
1115
|
const promptDiagnostics = promptsResult.diagnostics;
|
|
1110
1116
|
if (promptDiagnostics.length > 0) {
|
|
1111
1117
|
const warningLines = this.formatDiagnostics(promptDiagnostics, sourceInfos);
|
|
1112
|
-
this.
|
|
1113
|
-
this.
|
|
1118
|
+
this.loadedResourcesContainer.addChild(new Text(`${theme.fg("warning", "[Prompt conflicts]")}\n${warningLines}`, 0, 0));
|
|
1119
|
+
this.loadedResourcesContainer.addChild(new Spacer(1));
|
|
1114
1120
|
}
|
|
1115
1121
|
const extensionDiagnostics = [];
|
|
1116
1122
|
const extensionErrors = this.session.resourceLoader.getExtensions().errors;
|
|
@@ -1126,14 +1132,14 @@ export class InteractiveMode {
|
|
|
1126
1132
|
extensionDiagnostics.push(...shortcutDiagnostics);
|
|
1127
1133
|
if (extensionDiagnostics.length > 0) {
|
|
1128
1134
|
const warningLines = this.formatDiagnostics(extensionDiagnostics, sourceInfos);
|
|
1129
|
-
this.
|
|
1130
|
-
this.
|
|
1135
|
+
this.loadedResourcesContainer.addChild(new Text(`${theme.fg("warning", "[Extension issues]")}\n${warningLines}`, 0, 0));
|
|
1136
|
+
this.loadedResourcesContainer.addChild(new Spacer(1));
|
|
1131
1137
|
}
|
|
1132
1138
|
const themeDiagnostics = themesResult.diagnostics;
|
|
1133
1139
|
if (themeDiagnostics.length > 0) {
|
|
1134
1140
|
const warningLines = this.formatDiagnostics(themeDiagnostics, sourceInfos);
|
|
1135
|
-
this.
|
|
1136
|
-
this.
|
|
1141
|
+
this.loadedResourcesContainer.addChild(new Text(`${theme.fg("warning", "[Theme conflicts]")}\n${warningLines}`, 0, 0));
|
|
1142
|
+
this.loadedResourcesContainer.addChild(new Spacer(1));
|
|
1137
1143
|
}
|
|
1138
1144
|
}
|
|
1139
1145
|
}
|
|
@@ -1151,11 +1157,7 @@ export class InteractiveMode {
|
|
|
1151
1157
|
commandContextActions: {
|
|
1152
1158
|
waitForIdle: () => this.session.agent.waitForIdle(),
|
|
1153
1159
|
newSession: async (options) => {
|
|
1154
|
-
|
|
1155
|
-
this.loadingAnimation.stop();
|
|
1156
|
-
this.loadingAnimation = undefined;
|
|
1157
|
-
}
|
|
1158
|
-
this.statusContainer.clear();
|
|
1160
|
+
this.clearStatusIndicator();
|
|
1159
1161
|
try {
|
|
1160
1162
|
return await this.runtimeHost.newSession(options);
|
|
1161
1163
|
}
|
|
@@ -1225,8 +1227,13 @@ export class InteractiveMode {
|
|
|
1225
1227
|
this.footer.setAutoCompactEnabled(this.session.autoCompactionEnabled);
|
|
1226
1228
|
this.footerDataProvider.setCwd(this.sessionManager.getCwd());
|
|
1227
1229
|
this.hideThinkingBlock = this.settingsManager.getHideThinkingBlock();
|
|
1230
|
+
this.outputPad = this.settingsManager.getOutputPad();
|
|
1228
1231
|
this.ui.setShowHardwareCursor(this.settingsManager.getShowHardwareCursor());
|
|
1229
|
-
this.
|
|
1232
|
+
const clearOnShrink = this.settingsManager.getClearOnShrink();
|
|
1233
|
+
this.ui.setClearOnShrink(clearOnShrink);
|
|
1234
|
+
if (!clearOnShrink && !this.activeStatusIndicator) {
|
|
1235
|
+
this.statusContainer.clear();
|
|
1236
|
+
}
|
|
1230
1237
|
const editorPaddingX = this.settingsManager.getEditorPaddingX();
|
|
1231
1238
|
const autocompleteMaxVisible = this.settingsManager.getAutocompleteMaxVisible();
|
|
1232
1239
|
this.defaultEditor.setPaddingX(editorPaddingX);
|
|
@@ -1261,6 +1268,7 @@ export class InteractiveMode {
|
|
|
1261
1268
|
process.exit(1);
|
|
1262
1269
|
}
|
|
1263
1270
|
renderCurrentSessionState() {
|
|
1271
|
+
this.loadedResourcesContainer.clear();
|
|
1264
1272
|
this.chatContainer.clear();
|
|
1265
1273
|
this.pendingMessagesContainer.clear();
|
|
1266
1274
|
this.compactionQueuedMessages = [];
|
|
@@ -1338,36 +1346,41 @@ export class InteractiveMode {
|
|
|
1338
1346
|
this.footerDataProvider.setExtensionStatus(key, text);
|
|
1339
1347
|
this.ui.requestRender();
|
|
1340
1348
|
}
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1349
|
+
showStatusIndicator(indicator) {
|
|
1350
|
+
this.activeStatusIndicator?.dispose();
|
|
1351
|
+
this.activeStatusIndicator = indicator;
|
|
1352
|
+
this.statusContainer.clear();
|
|
1353
|
+
this.statusContainer.addChild(indicator);
|
|
1346
1354
|
}
|
|
1347
|
-
|
|
1348
|
-
if (this.
|
|
1349
|
-
|
|
1350
|
-
this.loadingAnimation = undefined;
|
|
1355
|
+
clearStatusIndicator(kind) {
|
|
1356
|
+
if (kind && this.activeStatusIndicator?.kind !== kind) {
|
|
1357
|
+
return;
|
|
1351
1358
|
}
|
|
1359
|
+
const hadActiveStatusIndicator = this.activeStatusIndicator !== undefined;
|
|
1360
|
+
this.activeStatusIndicator?.dispose();
|
|
1361
|
+
this.activeStatusIndicator = undefined;
|
|
1352
1362
|
this.statusContainer.clear();
|
|
1363
|
+
if (hadActiveStatusIndicator && this.ui.getClearOnShrink()) {
|
|
1364
|
+
this.statusContainer.addChild(this.idleStatus);
|
|
1365
|
+
}
|
|
1353
1366
|
}
|
|
1354
1367
|
setWorkingVisible(visible) {
|
|
1355
1368
|
this.workingVisible = visible;
|
|
1356
1369
|
if (!visible) {
|
|
1357
|
-
this.
|
|
1370
|
+
this.clearStatusIndicator("working");
|
|
1358
1371
|
this.ui.requestRender();
|
|
1359
1372
|
return;
|
|
1360
1373
|
}
|
|
1361
|
-
if (this.session.isStreaming &&
|
|
1362
|
-
this.
|
|
1363
|
-
this.loadingAnimation = this.createWorkingLoader();
|
|
1364
|
-
this.statusContainer.addChild(this.loadingAnimation);
|
|
1374
|
+
if (this.session.isStreaming && this.activeStatusIndicator?.kind !== "working") {
|
|
1375
|
+
this.showStatusIndicator(new WorkingStatusIndicator(this.ui, this.workingMessage ?? this.defaultWorkingMessage, this.workingIndicatorOptions));
|
|
1365
1376
|
}
|
|
1366
1377
|
this.ui.requestRender();
|
|
1367
1378
|
}
|
|
1368
1379
|
setWorkingIndicator(options) {
|
|
1369
1380
|
this.workingIndicatorOptions = options;
|
|
1370
|
-
this.
|
|
1381
|
+
if (this.activeStatusIndicator?.kind === "working") {
|
|
1382
|
+
this.activeStatusIndicator.setIndicator(options);
|
|
1383
|
+
}
|
|
1371
1384
|
this.ui.requestRender();
|
|
1372
1385
|
}
|
|
1373
1386
|
setHiddenThinkingLabel(label) {
|
|
@@ -1455,8 +1468,8 @@ export class InteractiveMode {
|
|
|
1455
1468
|
this.workingMessage = undefined;
|
|
1456
1469
|
this.workingVisible = true;
|
|
1457
1470
|
this.setWorkingIndicator();
|
|
1458
|
-
if (this.
|
|
1459
|
-
this.
|
|
1471
|
+
if (this.activeStatusIndicator?.kind === "working") {
|
|
1472
|
+
this.activeStatusIndicator.setMessage(`${this.defaultWorkingMessage} (${keyText("app.interrupt")} to interrupt)`);
|
|
1460
1473
|
}
|
|
1461
1474
|
this.setHiddenThinkingLabel();
|
|
1462
1475
|
}
|
|
@@ -1596,8 +1609,8 @@ export class InteractiveMode {
|
|
|
1596
1609
|
setStatus: (key, text) => this.setExtensionStatus(key, text),
|
|
1597
1610
|
setWorkingMessage: (message) => {
|
|
1598
1611
|
this.workingMessage = message;
|
|
1599
|
-
if (this.
|
|
1600
|
-
this.
|
|
1612
|
+
if (this.activeStatusIndicator?.kind === "working") {
|
|
1613
|
+
this.activeStatusIndicator.setMessage(message ?? this.defaultWorkingMessage);
|
|
1601
1614
|
}
|
|
1602
1615
|
},
|
|
1603
1616
|
setWorkingVisible: (visible) => this.setWorkingVisible(visible),
|
|
@@ -1741,7 +1754,7 @@ export class InteractiveMode {
|
|
|
1741
1754
|
}, () => {
|
|
1742
1755
|
this.hideExtensionEditor();
|
|
1743
1756
|
resolve(undefined);
|
|
1744
|
-
});
|
|
1757
|
+
}, undefined, this.settingsManager.getExternalEditorCommand());
|
|
1745
1758
|
this.editorContainer.clear();
|
|
1746
1759
|
this.editorContainer.addChild(this.extensionEditor);
|
|
1747
1760
|
this.ui.setFocus(this.extensionEditor);
|
|
@@ -2216,18 +2229,11 @@ export class InteractiveMode {
|
|
|
2216
2229
|
this.defaultEditor.onEscape = this.retryEscapeHandler;
|
|
2217
2230
|
this.retryEscapeHandler = undefined;
|
|
2218
2231
|
}
|
|
2219
|
-
if (this.retryCountdown) {
|
|
2220
|
-
this.retryCountdown.dispose();
|
|
2221
|
-
this.retryCountdown = undefined;
|
|
2222
|
-
}
|
|
2223
|
-
if (this.retryLoader) {
|
|
2224
|
-
this.retryLoader.stop();
|
|
2225
|
-
this.retryLoader = undefined;
|
|
2226
|
-
}
|
|
2227
|
-
this.stopWorkingLoader();
|
|
2228
2232
|
if (this.workingVisible) {
|
|
2229
|
-
this.
|
|
2230
|
-
|
|
2233
|
+
this.showStatusIndicator(new WorkingStatusIndicator(this.ui, this.workingMessage ?? this.defaultWorkingMessage, this.workingIndicatorOptions));
|
|
2234
|
+
}
|
|
2235
|
+
else {
|
|
2236
|
+
this.clearStatusIndicator();
|
|
2231
2237
|
}
|
|
2232
2238
|
this.ui.requestRender();
|
|
2233
2239
|
break;
|
|
@@ -2255,7 +2261,7 @@ export class InteractiveMode {
|
|
|
2255
2261
|
this.ui.requestRender();
|
|
2256
2262
|
}
|
|
2257
2263
|
else if (event.message.role === "assistant") {
|
|
2258
|
-
this.streamingComponent = new AssistantMessageComponent(undefined, this.hideThinkingBlock, this.getMarkdownThemeWithSettings(), this.hiddenThinkingLabel);
|
|
2264
|
+
this.streamingComponent = new AssistantMessageComponent(undefined, this.hideThinkingBlock, this.getMarkdownThemeWithSettings(), this.hiddenThinkingLabel, this.outputPad);
|
|
2259
2265
|
this.streamingMessage = event.message;
|
|
2260
2266
|
this.chatContainer.addChild(this.streamingComponent);
|
|
2261
2267
|
this.streamingComponent.updateContent(this.streamingMessage);
|
|
@@ -2363,11 +2369,7 @@ export class InteractiveMode {
|
|
|
2363
2369
|
if (this.settingsManager.getShowTerminalProgress()) {
|
|
2364
2370
|
this.ui.terminal.setProgress(false);
|
|
2365
2371
|
}
|
|
2366
|
-
|
|
2367
|
-
this.loadingAnimation.stop();
|
|
2368
|
-
this.loadingAnimation = undefined;
|
|
2369
|
-
this.statusContainer.clear();
|
|
2370
|
-
}
|
|
2372
|
+
this.clearStatusIndicator("working");
|
|
2371
2373
|
if (this.streamingComponent) {
|
|
2372
2374
|
this.chatContainer.removeChild(this.streamingComponent);
|
|
2373
2375
|
this.streamingComponent = undefined;
|
|
@@ -2386,13 +2388,7 @@ export class InteractiveMode {
|
|
|
2386
2388
|
this.defaultEditor.onEscape = () => {
|
|
2387
2389
|
this.session.abortCompaction();
|
|
2388
2390
|
};
|
|
2389
|
-
this.
|
|
2390
|
-
const cancelHint = `(${keyText("app.interrupt")} to cancel)`;
|
|
2391
|
-
const label = event.reason === "manual"
|
|
2392
|
-
? `Compacting context... ${cancelHint}`
|
|
2393
|
-
: `${event.reason === "overflow" ? "Context overflow detected, " : ""}Auto-compacting... ${cancelHint}`;
|
|
2394
|
-
this.autoCompactionLoader = new Loader(this.ui, (spinner) => theme.fg("accent", spinner), (text) => theme.fg("muted", text), label);
|
|
2395
|
-
this.statusContainer.addChild(this.autoCompactionLoader);
|
|
2391
|
+
this.showStatusIndicator(new CompactionStatusIndicator(this.ui, event.reason));
|
|
2396
2392
|
this.ui.requestRender();
|
|
2397
2393
|
break;
|
|
2398
2394
|
}
|
|
@@ -2404,11 +2400,7 @@ export class InteractiveMode {
|
|
|
2404
2400
|
this.defaultEditor.onEscape = this.autoCompactionEscapeHandler;
|
|
2405
2401
|
this.autoCompactionEscapeHandler = undefined;
|
|
2406
2402
|
}
|
|
2407
|
-
|
|
2408
|
-
this.autoCompactionLoader.stop();
|
|
2409
|
-
this.autoCompactionLoader = undefined;
|
|
2410
|
-
this.statusContainer.clear();
|
|
2411
|
-
}
|
|
2403
|
+
this.clearStatusIndicator("compaction");
|
|
2412
2404
|
if (event.aborted) {
|
|
2413
2405
|
if (event.reason === "manual") {
|
|
2414
2406
|
this.showError("Compaction cancelled");
|
|
@@ -2442,17 +2434,7 @@ export class InteractiveMode {
|
|
|
2442
2434
|
this.defaultEditor.onEscape = () => {
|
|
2443
2435
|
this.session.abortRetry();
|
|
2444
2436
|
};
|
|
2445
|
-
|
|
2446
|
-
this.statusContainer.clear();
|
|
2447
|
-
this.retryCountdown?.dispose();
|
|
2448
|
-
const retryMessage = (seconds) => `Retrying (${event.attempt}/${event.maxAttempts}) in ${seconds}s... (${keyText("app.interrupt")} to cancel)`;
|
|
2449
|
-
this.retryLoader = new Loader(this.ui, (spinner) => theme.fg("warning", spinner), (text) => theme.fg("muted", text), retryMessage(Math.ceil(event.delayMs / 1000)));
|
|
2450
|
-
this.retryCountdown = new CountdownTimer(event.delayMs, this.ui, (seconds) => {
|
|
2451
|
-
this.retryLoader?.setMessage(retryMessage(seconds));
|
|
2452
|
-
}, () => {
|
|
2453
|
-
this.retryCountdown = undefined;
|
|
2454
|
-
});
|
|
2455
|
-
this.statusContainer.addChild(this.retryLoader);
|
|
2437
|
+
this.showStatusIndicator(new RetryStatusIndicator(this.ui, event.attempt, event.maxAttempts, event.delayMs));
|
|
2456
2438
|
this.ui.requestRender();
|
|
2457
2439
|
break;
|
|
2458
2440
|
}
|
|
@@ -2462,16 +2444,7 @@ export class InteractiveMode {
|
|
|
2462
2444
|
this.defaultEditor.onEscape = this.retryEscapeHandler;
|
|
2463
2445
|
this.retryEscapeHandler = undefined;
|
|
2464
2446
|
}
|
|
2465
|
-
|
|
2466
|
-
this.retryCountdown.dispose();
|
|
2467
|
-
this.retryCountdown = undefined;
|
|
2468
|
-
}
|
|
2469
|
-
// Stop loader
|
|
2470
|
-
if (this.retryLoader) {
|
|
2471
|
-
this.retryLoader.stop();
|
|
2472
|
-
this.retryLoader = undefined;
|
|
2473
|
-
this.statusContainer.clear();
|
|
2474
|
-
}
|
|
2447
|
+
this.clearStatusIndicator("retry");
|
|
2475
2448
|
// Show error only on final failure (success shows normal response)
|
|
2476
2449
|
if (!event.success) {
|
|
2477
2450
|
this.showError(`Retry failed after ${event.attempt} attempts: ${event.finalError || "Unknown error"}`);
|
|
@@ -2562,12 +2535,12 @@ export class InteractiveMode {
|
|
|
2562
2535
|
// Render user message separately if present
|
|
2563
2536
|
if (skillBlock.userMessage) {
|
|
2564
2537
|
this.chatContainer.addChild(new Spacer(1));
|
|
2565
|
-
const userComponent = new UserMessageComponent(skillBlock.userMessage, this.getMarkdownThemeWithSettings());
|
|
2538
|
+
const userComponent = new UserMessageComponent(skillBlock.userMessage, this.getMarkdownThemeWithSettings(), this.outputPad);
|
|
2566
2539
|
this.chatContainer.addChild(userComponent);
|
|
2567
2540
|
}
|
|
2568
2541
|
}
|
|
2569
2542
|
else {
|
|
2570
|
-
const userComponent = new UserMessageComponent(textContent, this.getMarkdownThemeWithSettings());
|
|
2543
|
+
const userComponent = new UserMessageComponent(textContent, this.getMarkdownThemeWithSettings(), this.outputPad);
|
|
2571
2544
|
this.chatContainer.addChild(userComponent);
|
|
2572
2545
|
}
|
|
2573
2546
|
if (options?.populateHistory) {
|
|
@@ -2577,7 +2550,7 @@ export class InteractiveMode {
|
|
|
2577
2550
|
break;
|
|
2578
2551
|
}
|
|
2579
2552
|
case "assistant": {
|
|
2580
|
-
const assistantComponent = new AssistantMessageComponent(message, this.hideThinkingBlock, this.getMarkdownThemeWithSettings(), this.hiddenThinkingLabel);
|
|
2553
|
+
const assistantComponent = new AssistantMessageComponent(message, this.hideThinkingBlock, this.getMarkdownThemeWithSettings(), this.hiddenThinkingLabel, this.outputPad);
|
|
2581
2554
|
this.chatContainer.addChild(assistantComponent);
|
|
2582
2555
|
break;
|
|
2583
2556
|
}
|
|
@@ -2965,9 +2938,11 @@ export class InteractiveMode {
|
|
|
2965
2938
|
if (isExpandable(activeHeader)) {
|
|
2966
2939
|
activeHeader.setExpanded(expanded);
|
|
2967
2940
|
}
|
|
2968
|
-
for (const
|
|
2969
|
-
|
|
2970
|
-
child
|
|
2941
|
+
for (const container of [this.loadedResourcesContainer, this.chatContainer]) {
|
|
2942
|
+
for (const child of container.children) {
|
|
2943
|
+
if (isExpandable(child)) {
|
|
2944
|
+
child.setExpanded(expanded);
|
|
2945
|
+
}
|
|
2971
2946
|
}
|
|
2972
2947
|
}
|
|
2973
2948
|
this.ui.requestRender();
|
|
@@ -2987,10 +2962,9 @@ export class InteractiveMode {
|
|
|
2987
2962
|
this.showStatus(`Thinking blocks: ${this.hideThinkingBlock ? "hidden" : "visible"}`);
|
|
2988
2963
|
}
|
|
2989
2964
|
async openExternalEditor() {
|
|
2990
|
-
|
|
2991
|
-
const editorCmd = process.env.VISUAL || process.env.EDITOR;
|
|
2965
|
+
const editorCmd = this.settingsManager.getExternalEditorCommand();
|
|
2992
2966
|
if (!editorCmd) {
|
|
2993
|
-
this.showWarning("No editor configured. Set
|
|
2967
|
+
this.showWarning("No editor configured. Set externalEditor in settings.json or $VISUAL/$EDITOR.");
|
|
2994
2968
|
return;
|
|
2995
2969
|
}
|
|
2996
2970
|
const currentText = this.editor.getExpandedText?.() ?? this.editor.getText();
|
|
@@ -3294,6 +3268,7 @@ export class InteractiveMode {
|
|
|
3294
3268
|
showHardwareCursor: this.settingsManager.getShowHardwareCursor(),
|
|
3295
3269
|
defaultProjectTrust: this.settingsManager.getDefaultProjectTrust(),
|
|
3296
3270
|
editorPaddingX: this.settingsManager.getEditorPaddingX(),
|
|
3271
|
+
outputPad: this.settingsManager.getOutputPad(),
|
|
3297
3272
|
autocompleteMaxVisible: this.settingsManager.getAutocompleteMaxVisible(),
|
|
3298
3273
|
quietStartup: this.settingsManager.getQuietStartup(),
|
|
3299
3274
|
clearOnShrink: this.settingsManager.getClearOnShrink(),
|
|
@@ -3395,6 +3370,23 @@ export class InteractiveMode {
|
|
|
3395
3370
|
this.editor.setPaddingX(padding);
|
|
3396
3371
|
}
|
|
3397
3372
|
},
|
|
3373
|
+
onOutputPadChange: (padding) => {
|
|
3374
|
+
this.settingsManager.setOutputPad(padding);
|
|
3375
|
+
this.outputPad = padding;
|
|
3376
|
+
if (this.streamingComponent || this.session.isStreaming) {
|
|
3377
|
+
for (const child of this.chatContainer.children) {
|
|
3378
|
+
if (child instanceof AssistantMessageComponent || child instanceof UserMessageComponent) {
|
|
3379
|
+
child.setOutputPad(padding);
|
|
3380
|
+
}
|
|
3381
|
+
}
|
|
3382
|
+
if (this.streamingComponent) {
|
|
3383
|
+
this.streamingComponent.setOutputPad(padding);
|
|
3384
|
+
}
|
|
3385
|
+
this.ui.requestRender();
|
|
3386
|
+
return;
|
|
3387
|
+
}
|
|
3388
|
+
this.rebuildChatFromMessages();
|
|
3389
|
+
},
|
|
3398
3390
|
onAutocompleteMaxVisibleChange: (maxVisible) => {
|
|
3399
3391
|
this.settingsManager.setAutocompleteMaxVisible(maxVisible);
|
|
3400
3392
|
this.defaultEditor.setAutocompleteMaxVisible(maxVisible);
|
|
@@ -3405,6 +3397,9 @@ export class InteractiveMode {
|
|
|
3405
3397
|
onClearOnShrinkChange: (enabled) => {
|
|
3406
3398
|
this.settingsManager.setClearOnShrink(enabled);
|
|
3407
3399
|
this.ui.setClearOnShrink(enabled);
|
|
3400
|
+
if (!enabled && !this.activeStatusIndicator) {
|
|
3401
|
+
this.statusContainer.clear();
|
|
3402
|
+
}
|
|
3408
3403
|
},
|
|
3409
3404
|
onShowTerminalProgressChange: (enabled) => {
|
|
3410
3405
|
this.settingsManager.setShowTerminalProgress(enabled);
|
|
@@ -3722,16 +3717,16 @@ export class InteractiveMode {
|
|
|
3722
3717
|
break;
|
|
3723
3718
|
}
|
|
3724
3719
|
}
|
|
3725
|
-
// Set up escape handler and
|
|
3726
|
-
let
|
|
3720
|
+
// Set up escape handler and status indicator if summarizing
|
|
3721
|
+
let showingSummaryIndicator = false;
|
|
3727
3722
|
const originalOnEscape = this.defaultEditor.onEscape;
|
|
3728
3723
|
if (wantsSummary) {
|
|
3729
3724
|
this.defaultEditor.onEscape = () => {
|
|
3730
3725
|
this.session.abortBranchSummary();
|
|
3731
3726
|
};
|
|
3732
3727
|
this.chatContainer.addChild(new Spacer(1));
|
|
3733
|
-
|
|
3734
|
-
|
|
3728
|
+
this.showStatusIndicator(new BranchSummaryStatusIndicator(this.ui));
|
|
3729
|
+
showingSummaryIndicator = true;
|
|
3735
3730
|
this.ui.requestRender();
|
|
3736
3731
|
}
|
|
3737
3732
|
try {
|
|
@@ -3762,9 +3757,8 @@ export class InteractiveMode {
|
|
|
3762
3757
|
this.showError(error instanceof Error ? error.message : String(error));
|
|
3763
3758
|
}
|
|
3764
3759
|
finally {
|
|
3765
|
-
if (
|
|
3766
|
-
|
|
3767
|
-
this.statusContainer.clear();
|
|
3760
|
+
if (showingSummaryIndicator) {
|
|
3761
|
+
this.clearStatusIndicator("branchSummary");
|
|
3768
3762
|
}
|
|
3769
3763
|
this.defaultEditor.onEscape = originalOnEscape;
|
|
3770
3764
|
}
|
|
@@ -3805,11 +3799,7 @@ export class InteractiveMode {
|
|
|
3805
3799
|
});
|
|
3806
3800
|
}
|
|
3807
3801
|
async handleResumeSession(sessionPath, options) {
|
|
3808
|
-
|
|
3809
|
-
this.loadingAnimation.stop();
|
|
3810
|
-
this.loadingAnimation = undefined;
|
|
3811
|
-
}
|
|
3812
|
-
this.statusContainer.clear();
|
|
3802
|
+
this.clearStatusIndicator();
|
|
3813
3803
|
try {
|
|
3814
3804
|
const result = await this.runtimeHost.switchSession(sessionPath, {
|
|
3815
3805
|
withSession: options?.withSession,
|
|
@@ -4202,6 +4192,7 @@ export class InteractiveMode {
|
|
|
4202
4192
|
return;
|
|
4203
4193
|
}
|
|
4204
4194
|
this.hideThinkingBlock = this.settingsManager.getHideThinkingBlock();
|
|
4195
|
+
this.outputPad = this.settingsManager.getOutputPad();
|
|
4205
4196
|
this.rebuildChatFromMessages();
|
|
4206
4197
|
chatRestoredBeforeSessionStart = true;
|
|
4207
4198
|
};
|
|
@@ -4225,7 +4216,11 @@ export class InteractiveMode {
|
|
|
4225
4216
|
this.editor.setAutocompleteMaxVisible?.(autocompleteMaxVisible);
|
|
4226
4217
|
}
|
|
4227
4218
|
this.ui.setShowHardwareCursor(this.settingsManager.getShowHardwareCursor());
|
|
4228
|
-
this.
|
|
4219
|
+
const clearOnShrink = this.settingsManager.getClearOnShrink();
|
|
4220
|
+
this.ui.setClearOnShrink(clearOnShrink);
|
|
4221
|
+
if (!clearOnShrink && !this.activeStatusIndicator) {
|
|
4222
|
+
this.statusContainer.clear();
|
|
4223
|
+
}
|
|
4229
4224
|
this.setupAutocompleteProvider();
|
|
4230
4225
|
const runner = this.session.extensionRunner;
|
|
4231
4226
|
this.setupExtensionShortcuts(runner);
|
|
@@ -4304,11 +4299,7 @@ export class InteractiveMode {
|
|
|
4304
4299
|
return;
|
|
4305
4300
|
}
|
|
4306
4301
|
try {
|
|
4307
|
-
|
|
4308
|
-
this.loadingAnimation.stop();
|
|
4309
|
-
this.loadingAnimation = undefined;
|
|
4310
|
-
}
|
|
4311
|
-
this.statusContainer.clear();
|
|
4302
|
+
this.clearStatusIndicator();
|
|
4312
4303
|
const result = await this.runtimeHost.importFromJsonl(inputPath);
|
|
4313
4304
|
if (result.cancelled) {
|
|
4314
4305
|
this.showStatus("Import cancelled");
|
|
@@ -4634,11 +4625,7 @@ export class InteractiveMode {
|
|
|
4634
4625
|
this.ui.requestRender();
|
|
4635
4626
|
}
|
|
4636
4627
|
async handleClearCommand() {
|
|
4637
|
-
|
|
4638
|
-
this.loadingAnimation.stop();
|
|
4639
|
-
this.loadingAnimation = undefined;
|
|
4640
|
-
}
|
|
4641
|
-
this.statusContainer.clear();
|
|
4628
|
+
this.clearStatusIndicator();
|
|
4642
4629
|
try {
|
|
4643
4630
|
const result = await this.runtimeHost.newSession();
|
|
4644
4631
|
if (result.cancelled) {
|
|
@@ -4765,11 +4752,7 @@ export class InteractiveMode {
|
|
|
4765
4752
|
this.ui.requestRender();
|
|
4766
4753
|
}
|
|
4767
4754
|
async handleCompactCommand(customInstructions) {
|
|
4768
|
-
|
|
4769
|
-
this.loadingAnimation.stop();
|
|
4770
|
-
this.loadingAnimation = undefined;
|
|
4771
|
-
}
|
|
4772
|
-
this.statusContainer.clear();
|
|
4755
|
+
this.clearStatusIndicator();
|
|
4773
4756
|
try {
|
|
4774
4757
|
await this.session.compact(customInstructions);
|
|
4775
4758
|
}
|
|
@@ -4781,10 +4764,7 @@ export class InteractiveMode {
|
|
|
4781
4764
|
if (this.settingsManager.getShowTerminalProgress()) {
|
|
4782
4765
|
this.ui.terminal.setProgress(false);
|
|
4783
4766
|
}
|
|
4784
|
-
|
|
4785
|
-
this.loadingAnimation.stop();
|
|
4786
|
-
this.loadingAnimation = undefined;
|
|
4787
|
-
}
|
|
4767
|
+
this.clearStatusIndicator();
|
|
4788
4768
|
this.themeController.disableAutoSync();
|
|
4789
4769
|
this.clearExtensionTerminalInputListeners();
|
|
4790
4770
|
this.footer.dispose();
|