@code-yeongyu/senpi 2026.5.15 → 2026.5.18-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 +1172 -1161
- package/README.md +1 -2
- package/dist/cli/config-selector.d.ts.map +1 -1
- package/dist/cli/config-selector.js +1 -1
- package/dist/cli/config-selector.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +5 -1
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +12 -3
- package/dist/config.js.map +1 -1
- package/dist/core/agent-session.d.ts +11 -0
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +160 -13
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/compaction/compaction.d.ts +5 -3
- package/dist/core/compaction/compaction.d.ts.map +1 -1
- package/dist/core/compaction/compaction.js +22 -14
- package/dist/core/compaction/compaction.js.map +1 -1
- package/dist/core/dynamic-prompt/verification.d.ts +31 -0
- package/dist/core/dynamic-prompt/verification.d.ts.map +1 -1
- package/dist/core/dynamic-prompt/verification.js +41 -0
- package/dist/core/dynamic-prompt/verification.js.map +1 -1
- package/dist/core/extensions/builtin/compaction/context-reduction.d.ts +97 -0
- package/dist/core/extensions/builtin/compaction/context-reduction.d.ts.map +1 -0
- package/dist/core/extensions/builtin/compaction/context-reduction.js +420 -0
- package/dist/core/extensions/builtin/compaction/context-reduction.js.map +1 -0
- package/dist/core/extensions/builtin/compaction/index.d.ts.map +1 -1
- package/dist/core/extensions/builtin/compaction/index.js +168 -31
- package/dist/core/extensions/builtin/compaction/index.js.map +1 -1
- package/dist/core/extensions/builtin/compaction/openai-remote.d.ts +197 -0
- package/dist/core/extensions/builtin/compaction/openai-remote.d.ts.map +1 -0
- package/dist/core/extensions/builtin/compaction/openai-remote.js +690 -0
- package/dist/core/extensions/builtin/compaction/openai-remote.js.map +1 -0
- package/dist/core/extensions/builtin/compaction/prompts.d.ts +3 -3
- package/dist/core/extensions/builtin/compaction/prompts.d.ts.map +1 -1
- package/dist/core/extensions/builtin/compaction/prompts.js +0 -22
- package/dist/core/extensions/builtin/compaction/prompts.js.map +1 -1
- package/dist/core/extensions/builtin/compaction/repair-tool-pairs.d.ts +4 -0
- package/dist/core/extensions/builtin/compaction/repair-tool-pairs.d.ts.map +1 -0
- package/dist/core/extensions/builtin/compaction/repair-tool-pairs.js +48 -0
- package/dist/core/extensions/builtin/compaction/repair-tool-pairs.js.map +1 -0
- package/dist/core/extensions/builtin/compaction/speculative.d.ts +3 -1
- package/dist/core/extensions/builtin/compaction/speculative.d.ts.map +1 -1
- package/dist/core/extensions/builtin/compaction/speculative.js +80 -33
- package/dist/core/extensions/builtin/compaction/speculative.js.map +1 -1
- package/dist/core/extensions/builtin/compaction/todo-bridge.d.ts +8 -0
- package/dist/core/extensions/builtin/compaction/todo-bridge.d.ts.map +1 -1
- package/dist/core/extensions/builtin/compaction/todo-bridge.js +12 -6
- package/dist/core/extensions/builtin/compaction/todo-bridge.js.map +1 -1
- package/dist/core/extensions/builtin/diff.d.ts.map +1 -1
- package/dist/core/extensions/builtin/diff.js +1 -1
- package/dist/core/extensions/builtin/diff.js.map +1 -1
- package/dist/core/extensions/builtin/gpt-apply-patch/preview-format.d.ts.map +1 -1
- package/dist/core/extensions/builtin/gpt-apply-patch/preview-format.js +5 -128
- package/dist/core/extensions/builtin/gpt-apply-patch/preview-format.js.map +1 -1
- package/dist/core/extensions/builtin/index.d.ts.map +1 -1
- package/dist/core/extensions/builtin/index.js +0 -2
- package/dist/core/extensions/builtin/index.js.map +1 -1
- package/dist/core/extensions/builtin/openai-web-search/index.d.ts +6 -2
- package/dist/core/extensions/builtin/openai-web-search/index.d.ts.map +1 -1
- package/dist/core/extensions/builtin/openai-web-search/index.js +82 -10
- package/dist/core/extensions/builtin/openai-web-search/index.js.map +1 -1
- package/dist/core/extensions/builtin/permission-system/prompt.d.ts.map +1 -1
- package/dist/core/extensions/builtin/permission-system/prompt.js +0 -5
- package/dist/core/extensions/builtin/permission-system/prompt.js.map +1 -1
- package/dist/core/extensions/builtin/system-messages.d.ts +1 -1
- package/dist/core/extensions/builtin/system-messages.d.ts.map +1 -1
- package/dist/core/extensions/builtin/system-messages.js.map +1 -1
- package/dist/core/extensions/builtin/tool-pair-guard/index.d.ts +1 -1
- package/dist/core/extensions/builtin/tool-pair-guard/index.d.ts.map +1 -1
- package/dist/core/extensions/builtin/tool-pair-guard/index.js +8 -4
- package/dist/core/extensions/builtin/tool-pair-guard/index.js.map +1 -1
- package/dist/core/extensions/builtin/tool-pair-guard/sanitize-openai-chat-completions-payload.d.ts +3 -0
- package/dist/core/extensions/builtin/tool-pair-guard/sanitize-openai-chat-completions-payload.d.ts.map +1 -0
- package/dist/core/extensions/builtin/tool-pair-guard/sanitize-openai-chat-completions-payload.js +89 -0
- package/dist/core/extensions/builtin/tool-pair-guard/sanitize-openai-chat-completions-payload.js.map +1 -0
- package/dist/core/extensions/builtin/tool-pair-guard/sanitize-openai-responses-payload.d.ts +3 -0
- package/dist/core/extensions/builtin/tool-pair-guard/sanitize-openai-responses-payload.d.ts.map +1 -0
- package/dist/core/extensions/builtin/tool-pair-guard/sanitize-openai-responses-payload.js +122 -0
- package/dist/core/extensions/builtin/tool-pair-guard/sanitize-openai-responses-payload.js.map +1 -0
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +2 -0
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/runner.d.ts +3 -0
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +18 -0
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +22 -0
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/messages.d.ts +3 -3
- package/dist/core/messages.d.ts.map +1 -1
- package/dist/core/messages.js +5 -10
- package/dist/core/messages.js.map +1 -1
- package/dist/core/model-registry.d.ts +1 -0
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +66 -9
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/package-manager.d.ts +5 -0
- package/dist/core/package-manager.d.ts.map +1 -1
- package/dist/core/package-manager.js +72 -31
- package/dist/core/package-manager.js.map +1 -1
- package/dist/core/prompt-templates.d.ts.map +1 -1
- package/dist/core/prompt-templates.js +6 -4
- package/dist/core/prompt-templates.js.map +1 -1
- package/dist/core/sdk.d.ts +1 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +7 -22
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +39 -9
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/settings-manager.d.ts +0 -5
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/skills.d.ts.map +1 -1
- package/dist/core/skills.js +2 -5
- package/dist/core/skills.js.map +1 -1
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +3 -2
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/thinking-levels.d.ts +6 -0
- package/dist/core/thinking-levels.d.ts.map +1 -0
- package/dist/core/thinking-levels.js +36 -0
- package/dist/core/thinking-levels.js.map +1 -0
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +15 -1
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/diff-render.d.ts +13 -0
- package/dist/core/tools/diff-render.d.ts.map +1 -0
- package/dist/core/tools/diff-render.js +130 -0
- package/dist/core/tools/diff-render.js.map +1 -0
- package/dist/core/tools/edit.d.ts.map +1 -1
- package/dist/core/tools/edit.js +8 -3
- package/dist/core/tools/edit.js.map +1 -1
- package/dist/core/tools/write.d.ts.map +1 -1
- package/dist/core/tools/write.js +28 -7
- package/dist/core/tools/write.js.map +1 -1
- package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/compaction-summary-message.js +20 -2
- package/dist/modes/interactive/components/compaction-summary-message.js.map +1 -1
- package/dist/modes/interactive/components/config-selector.d.ts +2 -2
- package/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/config-selector.js +7 -4
- package/dist/modes/interactive/components/config-selector.js.map +1 -1
- package/dist/modes/interactive/components/footer.d.ts +0 -1
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +42 -44
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/components/keybinding-hints.d.ts.map +1 -1
- package/dist/modes/interactive/components/keybinding-hints.js +3 -1
- package/dist/modes/interactive/components/keybinding-hints.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +9 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +177 -82
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/session-info-format.d.ts +3 -0
- package/dist/modes/interactive/session-info-format.d.ts.map +1 -0
- package/dist/modes/interactive/session-info-format.js +44 -0
- package/dist/modes/interactive/session-info-format.js.map +1 -0
- package/dist/modes/interactive/working-status.d.ts +21 -0
- package/dist/modes/interactive/working-status.d.ts.map +1 -0
- package/dist/modes/interactive/working-status.js +71 -0
- package/dist/modes/interactive/working-status.js.map +1 -0
- package/dist/package-manager-cli.d.ts.map +1 -1
- package/dist/package-manager-cli.js +3 -4
- package/dist/package-manager-cli.js.map +1 -1
- package/dist/senpi +5 -1
- package/dist/utils/child-process.d.ts +7 -1
- package/dist/utils/child-process.d.ts.map +1 -1
- package/dist/utils/child-process.js +60 -7
- package/dist/utils/child-process.js.map +1 -1
- package/dist/utils/clipboard-image.d.ts.map +1 -1
- package/dist/utils/clipboard-image.js +1 -1
- package/dist/utils/clipboard-image.js.map +1 -1
- package/dist/utils/tools-manager.d.ts.map +1 -1
- package/dist/utils/tools-manager.js +4 -1
- package/dist/utils/tools-manager.js.map +1 -1
- package/docs/custom-provider.md +55 -0
- package/docs/extensions.md +1 -2
- package/docs/index.md +0 -1
- package/docs/models.md +9 -0
- package/docs/sdk.md +0 -1
- package/docs/settings.md +2 -32
- package/docs/skills.md +3 -4
- package/docs/termux.md +2 -2
- package/docs/usage.md +1 -1
- package/examples/README.md +1 -1
- package/examples/extensions/README.md +0 -1
- 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/overlay-qa-tests.ts +1 -1
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/package.json +6 -6
- package/dist/core/extensions/builtin/background-task/cancel-tool.d.ts +0 -10
- package/dist/core/extensions/builtin/background-task/cancel-tool.d.ts.map +0 -1
- package/dist/core/extensions/builtin/background-task/cancel-tool.js +0 -109
- package/dist/core/extensions/builtin/background-task/cancel-tool.js.map +0 -1
- package/dist/core/extensions/builtin/background-task/index.d.ts +0 -3
- package/dist/core/extensions/builtin/background-task/index.d.ts.map +0 -1
- package/dist/core/extensions/builtin/background-task/index.js +0 -207
- package/dist/core/extensions/builtin/background-task/index.js.map +0 -1
- package/dist/core/extensions/builtin/background-task/manager.d.ts +0 -17
- package/dist/core/extensions/builtin/background-task/manager.d.ts.map +0 -1
- package/dist/core/extensions/builtin/background-task/manager.js +0 -114
- package/dist/core/extensions/builtin/background-task/manager.js.map +0 -1
- package/dist/core/extensions/builtin/background-task/notification.d.ts +0 -22
- package/dist/core/extensions/builtin/background-task/notification.d.ts.map +0 -1
- package/dist/core/extensions/builtin/background-task/notification.js +0 -105
- package/dist/core/extensions/builtin/background-task/notification.js.map +0 -1
- package/dist/core/extensions/builtin/background-task/output-tool.d.ts +0 -11
- package/dist/core/extensions/builtin/background-task/output-tool.d.ts.map +0 -1
- package/dist/core/extensions/builtin/background-task/output-tool.js +0 -127
- package/dist/core/extensions/builtin/background-task/output-tool.js.map +0 -1
- package/dist/core/extensions/builtin/background-task/spawner.d.ts +0 -8
- package/dist/core/extensions/builtin/background-task/spawner.d.ts.map +0 -1
- package/dist/core/extensions/builtin/background-task/spawner.js +0 -207
- package/dist/core/extensions/builtin/background-task/spawner.js.map +0 -1
- package/dist/core/extensions/builtin/background-task/task-tool.d.ts +0 -20
- package/dist/core/extensions/builtin/background-task/task-tool.d.ts.map +0 -1
- package/dist/core/extensions/builtin/background-task/task-tool.js +0 -302
- package/dist/core/extensions/builtin/background-task/task-tool.js.map +0 -1
- package/dist/core/extensions/builtin/background-task/types.d.ts +0 -72
- package/dist/core/extensions/builtin/background-task/types.d.ts.map +0 -1
- package/dist/core/extensions/builtin/background-task/types.js +0 -32
- package/dist/core/extensions/builtin/background-task/types.js.map +0 -1
- package/docs/agents.md +0 -348
- package/examples/extensions/subagent/README.md +0 -172
- package/examples/extensions/subagent/agents/planner.md +0 -37
- package/examples/extensions/subagent/agents/reviewer.md +0 -35
- package/examples/extensions/subagent/agents/scout.md +0 -50
- package/examples/extensions/subagent/agents/worker.md +0 -24
- package/examples/extensions/subagent/agents.ts +0 -126
- package/examples/extensions/subagent/index.ts +0 -987
- package/examples/extensions/subagent/prompts/implement-and-review.md +0 -10
- package/examples/extensions/subagent/prompts/implement.md +0 -10
- package/examples/extensions/subagent/prompts/scout-and-plan.md +0 -9
|
@@ -58,8 +58,10 @@ import { ToolExecutionComponent } from "./components/tool-execution.js";
|
|
|
58
58
|
import { TreeSelectorComponent } from "./components/tree-selector.js";
|
|
59
59
|
import { UserMessageComponent } from "./components/user-message.js";
|
|
60
60
|
import { UserMessageSelectorComponent } from "./components/user-message-selector.js";
|
|
61
|
+
import { formatSessionInfo } from "./session-info-format.js";
|
|
61
62
|
import { resolveStartupToolPaths } from "./startup-tools.js";
|
|
62
63
|
import { getAvailableThemes, getAvailableThemesWithPaths, getEditorTheme, getMarkdownTheme, getThemeByName, initTheme, onThemeChange, setRegisteredThemes, setTheme, setThemeInstance, stopThemeWatcher, Theme, theme, } from "./theme/theme.js";
|
|
64
|
+
import { blendWorkingStatusShimmerRgbColor, formatWorkingStatusMessageFrame, } from "./working-status.js";
|
|
63
65
|
function isExpandable(obj) {
|
|
64
66
|
return typeof obj === "object" && obj !== null && "setExpanded" in obj && typeof obj.setExpanded === "function";
|
|
65
67
|
}
|
|
@@ -76,6 +78,48 @@ class ExpandableText extends Text {
|
|
|
76
78
|
}
|
|
77
79
|
}
|
|
78
80
|
const DEAD_TERMINAL_ERROR_CODES = new Set(["EIO", "EPIPE", "ENOTCONN"]);
|
|
81
|
+
const DEFAULT_WORKING_STATUS_REFRESH_INTERVAL_MS = 600;
|
|
82
|
+
const DEFAULT_WORKING_STATUS_MESSAGE_ANIMATION_INTERVAL_MS = 32;
|
|
83
|
+
const RGB_FOREGROUND_PATTERN = /\x1b\[38;2;(\d+);(\d+);(\d+)m/;
|
|
84
|
+
const DARK_DEFAULT_WORKING_TEXT_RGB = { r: 229, g: 229, b: 231 };
|
|
85
|
+
const LIGHT_DEFAULT_WORKING_TEXT_RGB = { r: 17, g: 17, b: 17 };
|
|
86
|
+
const DARK_DEFAULT_WORKING_BASE_RGB = { r: 102, g: 102, b: 102 };
|
|
87
|
+
const LIGHT_DEFAULT_WORKING_BASE_RGB = { r: 118, g: 118, b: 118 };
|
|
88
|
+
function parseAnsiRgbForeground(ansi) {
|
|
89
|
+
const match = RGB_FOREGROUND_PATTERN.exec(ansi);
|
|
90
|
+
const red = match?.[1];
|
|
91
|
+
const green = match?.[2];
|
|
92
|
+
const blue = match?.[3];
|
|
93
|
+
if (red === undefined || green === undefined || blue === undefined) {
|
|
94
|
+
return undefined;
|
|
95
|
+
}
|
|
96
|
+
return {
|
|
97
|
+
r: Number.parseInt(red, 10),
|
|
98
|
+
g: Number.parseInt(green, 10),
|
|
99
|
+
b: Number.parseInt(blue, 10),
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
function isWorkingLightTheme() {
|
|
103
|
+
return theme.name?.toLowerCase().includes("light") ?? false;
|
|
104
|
+
}
|
|
105
|
+
function formatWorkingStatusShimmerText(text, intensity) {
|
|
106
|
+
if (theme.getColorMode() !== "truecolor") {
|
|
107
|
+
if (intensity < 0.2) {
|
|
108
|
+
return theme.fg("dim", text);
|
|
109
|
+
}
|
|
110
|
+
if (intensity < 0.6) {
|
|
111
|
+
return theme.fg("text", text);
|
|
112
|
+
}
|
|
113
|
+
return theme.bold(theme.fg("text", text));
|
|
114
|
+
}
|
|
115
|
+
const lightTheme = isWorkingLightTheme();
|
|
116
|
+
const highlight = parseAnsiRgbForeground(theme.getFgAnsi("dim")) ??
|
|
117
|
+
(lightTheme ? LIGHT_DEFAULT_WORKING_BASE_RGB : DARK_DEFAULT_WORKING_BASE_RGB);
|
|
118
|
+
const base = parseAnsiRgbForeground(theme.getFgAnsi("text")) ??
|
|
119
|
+
(lightTheme ? LIGHT_DEFAULT_WORKING_TEXT_RGB : DARK_DEFAULT_WORKING_TEXT_RGB);
|
|
120
|
+
const color = blendWorkingStatusShimmerRgbColor(highlight, base, intensity * 0.9);
|
|
121
|
+
return `\x1b[1m\x1b[38;2;${color.r};${color.g};${color.b}m${text}\x1b[39m\x1b[22m`;
|
|
122
|
+
}
|
|
79
123
|
function isDeadTerminalError(error) {
|
|
80
124
|
if (!error || typeof error !== "object" || !("code" in error)) {
|
|
81
125
|
return false;
|
|
@@ -129,7 +173,9 @@ export class InteractiveMode {
|
|
|
129
173
|
workingMessage = undefined;
|
|
130
174
|
workingVisible = true;
|
|
131
175
|
workingIndicatorOptions = undefined;
|
|
132
|
-
|
|
176
|
+
workingStartedAt = undefined;
|
|
177
|
+
workingElapsedIntervalId = undefined;
|
|
178
|
+
defaultWorkingMessage = "Working";
|
|
133
179
|
defaultHiddenThinkingLabel = "Thinking...";
|
|
134
180
|
hiddenThinkingLabel = this.defaultHiddenThinkingLabel;
|
|
135
181
|
lastSigintTime = 0;
|
|
@@ -166,6 +212,7 @@ export class InteractiveMode {
|
|
|
166
212
|
// Auto-compaction state
|
|
167
213
|
autoCompactionLoader = undefined;
|
|
168
214
|
autoCompactionEscapeHandler;
|
|
215
|
+
autoCompactionProgressText = "";
|
|
169
216
|
// Auto-retry state
|
|
170
217
|
retryLoader = undefined;
|
|
171
218
|
retryCountdown = undefined;
|
|
@@ -391,6 +438,19 @@ export class InteractiveMode {
|
|
|
391
438
|
// Startup should never wait for tool downloads. Missing tools are resolved
|
|
392
439
|
// lazily by the tools that need them.
|
|
393
440
|
this.fdPath = resolveStartupToolPaths().fdPath;
|
|
441
|
+
if (this.session.scopedModels.length > 0 && (this.options.verbose || !this.settingsManager.getQuietStartup())) {
|
|
442
|
+
const modelList = this.session.scopedModels
|
|
443
|
+
.map((sm) => {
|
|
444
|
+
const thinkingStr = sm.thinkingLevel ? `:${sm.thinkingLevel}` : "";
|
|
445
|
+
return `${sm.model.id}${thinkingStr}`;
|
|
446
|
+
})
|
|
447
|
+
.join(", ");
|
|
448
|
+
const cycleKeys = this.keybindings.getKeys("app.model.cycleForward");
|
|
449
|
+
const cycleHint = cycleKeys.length > 0
|
|
450
|
+
? theme.fg("muted", ` (${formatKeyText(cycleKeys.join("/"), { capitalize: true })} to cycle)`)
|
|
451
|
+
: "";
|
|
452
|
+
console.log(theme.fg("dim", `Model scope: ${modelList}${cycleHint}`));
|
|
453
|
+
}
|
|
394
454
|
// Add header container as first child
|
|
395
455
|
this.ui.addChild(this.headerContainer);
|
|
396
456
|
// Add header with keybindings from config (unless silenced)
|
|
@@ -1097,11 +1157,7 @@ export class InteractiveMode {
|
|
|
1097
1157
|
commandContextActions: {
|
|
1098
1158
|
waitForIdle: () => this.session.agent.waitForIdle(),
|
|
1099
1159
|
newSession: async (options) => {
|
|
1100
|
-
|
|
1101
|
-
this.loadingAnimation.stop();
|
|
1102
|
-
this.loadingAnimation = undefined;
|
|
1103
|
-
}
|
|
1104
|
-
this.statusContainer.clear();
|
|
1160
|
+
this.stopWorkingLoader();
|
|
1105
1161
|
try {
|
|
1106
1162
|
const result = await this.runtimeHost.newSession(options);
|
|
1107
1163
|
if (!result.cancelled) {
|
|
@@ -1285,10 +1341,48 @@ export class InteractiveMode {
|
|
|
1285
1341
|
getWorkingLoaderMessage() {
|
|
1286
1342
|
return this.workingMessage ?? this.defaultWorkingMessage;
|
|
1287
1343
|
}
|
|
1344
|
+
getWorkingElapsedSeconds() {
|
|
1345
|
+
if (this.workingStartedAt === undefined) {
|
|
1346
|
+
return 0;
|
|
1347
|
+
}
|
|
1348
|
+
return Math.max(0, Math.floor((Date.now() - this.workingStartedAt) / 1000));
|
|
1349
|
+
}
|
|
1350
|
+
refreshWorkingLoaderMessage() {
|
|
1351
|
+
this.loadingAnimation?.setMessage(this.getWorkingLoaderMessage());
|
|
1352
|
+
}
|
|
1353
|
+
startWorkingElapsedTimer() {
|
|
1354
|
+
this.stopWorkingElapsedTimer();
|
|
1355
|
+
this.workingStartedAt = Date.now();
|
|
1356
|
+
this.workingElapsedIntervalId = setInterval(() => {
|
|
1357
|
+
this.refreshWorkingLoaderMessage();
|
|
1358
|
+
}, DEFAULT_WORKING_STATUS_REFRESH_INTERVAL_MS);
|
|
1359
|
+
}
|
|
1360
|
+
stopWorkingElapsedTimer() {
|
|
1361
|
+
if (this.workingElapsedIntervalId) {
|
|
1362
|
+
clearInterval(this.workingElapsedIntervalId);
|
|
1363
|
+
this.workingElapsedIntervalId = undefined;
|
|
1364
|
+
}
|
|
1365
|
+
}
|
|
1366
|
+
getWorkingIndicatorOptions() {
|
|
1367
|
+
return (this.workingIndicatorOptions ?? {
|
|
1368
|
+
frames: [theme.fg("accent", "•")],
|
|
1369
|
+
intervalMs: DEFAULT_WORKING_STATUS_REFRESH_INTERVAL_MS,
|
|
1370
|
+
messageFormatter: (message, animationElapsedMs) => formatWorkingStatusMessageFrame(message, this.getWorkingElapsedSeconds(), keyText("app.interrupt"), animationElapsedMs, {
|
|
1371
|
+
base: (text) => theme.fg("dim", text),
|
|
1372
|
+
glow: (text) => theme.fg("text", text),
|
|
1373
|
+
highlight: (text) => theme.bold(theme.fg("text", text)),
|
|
1374
|
+
shimmer: formatWorkingStatusShimmerText,
|
|
1375
|
+
suffix: (text) => theme.fg("dim", text),
|
|
1376
|
+
}),
|
|
1377
|
+
messageIntervalMs: DEFAULT_WORKING_STATUS_MESSAGE_ANIMATION_INTERVAL_MS,
|
|
1378
|
+
});
|
|
1379
|
+
}
|
|
1288
1380
|
createWorkingLoader() {
|
|
1289
|
-
return new Loader(this.ui, (spinner) => theme.fg("accent", spinner), (text) => theme.fg("muted", text), this.getWorkingLoaderMessage(), this.
|
|
1381
|
+
return new Loader(this.ui, (spinner) => theme.fg("accent", spinner), (text) => theme.fg("muted", text), this.getWorkingLoaderMessage(), this.getWorkingIndicatorOptions());
|
|
1290
1382
|
}
|
|
1291
1383
|
stopWorkingLoader() {
|
|
1384
|
+
this.stopWorkingElapsedTimer();
|
|
1385
|
+
this.workingStartedAt = undefined;
|
|
1292
1386
|
if (this.loadingAnimation) {
|
|
1293
1387
|
this.loadingAnimation.stop();
|
|
1294
1388
|
this.loadingAnimation = undefined;
|
|
@@ -1304,6 +1398,7 @@ export class InteractiveMode {
|
|
|
1304
1398
|
}
|
|
1305
1399
|
if (this.session.isStreaming && !this.loadingAnimation) {
|
|
1306
1400
|
this.statusContainer.clear();
|
|
1401
|
+
this.startWorkingElapsedTimer();
|
|
1307
1402
|
this.loadingAnimation = this.createWorkingLoader();
|
|
1308
1403
|
this.statusContainer.addChild(this.loadingAnimation);
|
|
1309
1404
|
}
|
|
@@ -1311,7 +1406,7 @@ export class InteractiveMode {
|
|
|
1311
1406
|
}
|
|
1312
1407
|
setWorkingIndicator(options) {
|
|
1313
1408
|
this.workingIndicatorOptions = options;
|
|
1314
|
-
this.loadingAnimation?.setIndicator(
|
|
1409
|
+
this.loadingAnimation?.setIndicator(this.getWorkingIndicatorOptions());
|
|
1315
1410
|
this.ui.requestRender();
|
|
1316
1411
|
}
|
|
1317
1412
|
setHiddenThinkingLabel(label) {
|
|
@@ -1399,9 +1494,7 @@ export class InteractiveMode {
|
|
|
1399
1494
|
this.workingMessage = undefined;
|
|
1400
1495
|
this.workingVisible = true;
|
|
1401
1496
|
this.setWorkingIndicator();
|
|
1402
|
-
|
|
1403
|
-
this.loadingAnimation.setMessage(`${this.defaultWorkingMessage} (${keyText("app.interrupt")} to interrupt)`);
|
|
1404
|
-
}
|
|
1497
|
+
this.refreshWorkingLoaderMessage();
|
|
1405
1498
|
this.setHiddenThinkingLabel();
|
|
1406
1499
|
}
|
|
1407
1500
|
// Maximum total widget lines to prevent viewport overflow
|
|
@@ -1526,9 +1619,7 @@ export class InteractiveMode {
|
|
|
1526
1619
|
setStatus: (key, text) => this.setExtensionStatus(key, text),
|
|
1527
1620
|
setWorkingMessage: (message) => {
|
|
1528
1621
|
this.workingMessage = message;
|
|
1529
|
-
|
|
1530
|
-
this.loadingAnimation.setMessage(message ?? this.defaultWorkingMessage);
|
|
1531
|
-
}
|
|
1622
|
+
this.refreshWorkingLoaderMessage();
|
|
1532
1623
|
},
|
|
1533
1624
|
setWorkingVisible: (visible) => this.setWorkingVisible(visible),
|
|
1534
1625
|
setWorkingIndicator: (options) => this.setWorkingIndicator(options),
|
|
@@ -1859,8 +1950,8 @@ export class InteractiveMode {
|
|
|
1859
1950
|
// Set up handlers on defaultEditor - they use this.editor for text access
|
|
1860
1951
|
// so they work correctly regardless of which editor is active
|
|
1861
1952
|
this.defaultEditor.onEscape = () => {
|
|
1862
|
-
if (this.session.isStreaming) {
|
|
1863
|
-
this.
|
|
1953
|
+
if (this.session.isStreaming || this.session.retryAttempt > 0) {
|
|
1954
|
+
void this.abortAndFireQueuedMessages();
|
|
1864
1955
|
}
|
|
1865
1956
|
else if (this.session.isBashRunning) {
|
|
1866
1957
|
this.session.abortBash();
|
|
@@ -2149,6 +2240,7 @@ export class InteractiveMode {
|
|
|
2149
2240
|
}
|
|
2150
2241
|
this.stopWorkingLoader();
|
|
2151
2242
|
if (this.workingVisible) {
|
|
2243
|
+
this.startWorkingElapsedTimer();
|
|
2152
2244
|
this.loadingAnimation = this.createWorkingLoader();
|
|
2153
2245
|
this.statusContainer.addChild(this.loadingAnimation);
|
|
2154
2246
|
}
|
|
@@ -2290,11 +2382,7 @@ export class InteractiveMode {
|
|
|
2290
2382
|
if (this.settingsManager.getShowTerminalProgress()) {
|
|
2291
2383
|
this.ui.terminal.setProgress(false);
|
|
2292
2384
|
}
|
|
2293
|
-
|
|
2294
|
-
this.loadingAnimation.stop();
|
|
2295
|
-
this.loadingAnimation = undefined;
|
|
2296
|
-
this.statusContainer.clear();
|
|
2297
|
-
}
|
|
2385
|
+
this.stopWorkingLoader();
|
|
2298
2386
|
if (this.streamingComponent) {
|
|
2299
2387
|
this.chatContainer.removeChild(this.streamingComponent);
|
|
2300
2388
|
this.streamingComponent = undefined;
|
|
@@ -2315,11 +2403,31 @@ export class InteractiveMode {
|
|
|
2315
2403
|
};
|
|
2316
2404
|
this.statusContainer.clear();
|
|
2317
2405
|
const cancelHint = `(${keyText("app.interrupt")} to cancel)`;
|
|
2318
|
-
const label = event.reason === "
|
|
2319
|
-
? `
|
|
2320
|
-
:
|
|
2406
|
+
const label = event.reason === "threshold"
|
|
2407
|
+
? `Auto-compacting... ${cancelHint}`
|
|
2408
|
+
: event.reason === "overflow"
|
|
2409
|
+
? `Context overflow detected, compacting... ${cancelHint}`
|
|
2410
|
+
: event.reason === "pre_prompt"
|
|
2411
|
+
? `Compacting before next prompt... ${cancelHint}`
|
|
2412
|
+
: `Compacting context... ${cancelHint}`;
|
|
2321
2413
|
this.autoCompactionLoader = new Loader(this.ui, (spinner) => theme.fg("accent", spinner), (text) => theme.fg("muted", text), label);
|
|
2322
2414
|
this.statusContainer.addChild(this.autoCompactionLoader);
|
|
2415
|
+
this.autoCompactionProgressText = "";
|
|
2416
|
+
this.ui.requestRender();
|
|
2417
|
+
break;
|
|
2418
|
+
}
|
|
2419
|
+
case "compaction_progress": {
|
|
2420
|
+
if (!this.autoCompactionLoader)
|
|
2421
|
+
break;
|
|
2422
|
+
const nextText = event.text !== undefined ? event.text : `${this.autoCompactionProgressText}${event.delta ?? ""}`;
|
|
2423
|
+
if (!nextText)
|
|
2424
|
+
break;
|
|
2425
|
+
this.autoCompactionProgressText = nextText;
|
|
2426
|
+
const preview = nextText.length > 4_000 ? `...${nextText.slice(nextText.length - 4_000)}` : nextText;
|
|
2427
|
+
this.statusContainer.clear();
|
|
2428
|
+
this.statusContainer.addChild(this.autoCompactionLoader);
|
|
2429
|
+
this.statusContainer.addChild(new Spacer(1));
|
|
2430
|
+
this.statusContainer.addChild(new Text(theme.fg("muted", preview), 1, 0));
|
|
2323
2431
|
this.ui.requestRender();
|
|
2324
2432
|
break;
|
|
2325
2433
|
}
|
|
@@ -2334,6 +2442,7 @@ export class InteractiveMode {
|
|
|
2334
2442
|
if (this.autoCompactionLoader) {
|
|
2335
2443
|
this.autoCompactionLoader.stop();
|
|
2336
2444
|
this.autoCompactionLoader = undefined;
|
|
2445
|
+
this.autoCompactionProgressText = "";
|
|
2337
2446
|
this.statusContainer.clear();
|
|
2338
2447
|
}
|
|
2339
2448
|
if (event.aborted) {
|
|
@@ -2347,7 +2456,7 @@ export class InteractiveMode {
|
|
|
2347
2456
|
else if (event.result) {
|
|
2348
2457
|
this.chatContainer.clear();
|
|
2349
2458
|
this.rebuildChatFromMessages();
|
|
2350
|
-
this.addMessageToChat(createCompactionSummaryMessage(event.result.summary, event.result.tokensBefore, new Date().toISOString()));
|
|
2459
|
+
this.addMessageToChat(createCompactionSummaryMessage(event.result.summary, event.result.tokensBefore, new Date().toISOString(), event.result.details));
|
|
2351
2460
|
this.footer.invalidate();
|
|
2352
2461
|
}
|
|
2353
2462
|
else if (event.errorMessage) {
|
|
@@ -2364,11 +2473,11 @@ export class InteractiveMode {
|
|
|
2364
2473
|
break;
|
|
2365
2474
|
}
|
|
2366
2475
|
case "auto_retry_start": {
|
|
2367
|
-
//
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2476
|
+
// During retry waits, isStreaming flips false between attempts. The main Esc handler
|
|
2477
|
+
// keys off both isStreaming and retryAttempt so we keep the same close-out path here;
|
|
2478
|
+
// no separate retry-only handler is installed (the prior one only called
|
|
2479
|
+
// session.abortRetry() and left queued steering messages stranded).
|
|
2480
|
+
this.retryEscapeHandler = undefined;
|
|
2372
2481
|
// Show retry indicator
|
|
2373
2482
|
this.statusContainer.clear();
|
|
2374
2483
|
this.retryCountdown?.dispose();
|
|
@@ -2932,6 +3041,7 @@ export class InteractiveMode {
|
|
|
2932
3041
|
showError(errorMessage) {
|
|
2933
3042
|
this.chatContainer.addChild(new Spacer(1));
|
|
2934
3043
|
this.chatContainer.addChild(new Text(theme.fg("error", `Error: ${errorMessage}`), 1, 0));
|
|
3044
|
+
this.chatContainer.addChild(new Spacer(1));
|
|
2935
3045
|
this.ui.requestRender();
|
|
2936
3046
|
}
|
|
2937
3047
|
showWarning(warningMessage) {
|
|
@@ -3021,7 +3131,7 @@ export class InteractiveMode {
|
|
|
3021
3131
|
if (allQueued.length === 0) {
|
|
3022
3132
|
this.updatePendingMessagesDisplay();
|
|
3023
3133
|
if (options?.abort) {
|
|
3024
|
-
this.
|
|
3134
|
+
void this.session.abort();
|
|
3025
3135
|
}
|
|
3026
3136
|
return 0;
|
|
3027
3137
|
}
|
|
@@ -3031,7 +3141,36 @@ export class InteractiveMode {
|
|
|
3031
3141
|
this.editor.setText(combinedText);
|
|
3032
3142
|
this.updatePendingMessagesDisplay();
|
|
3033
3143
|
if (options?.abort) {
|
|
3034
|
-
this.
|
|
3144
|
+
void this.session.abort();
|
|
3145
|
+
}
|
|
3146
|
+
return allQueued.length;
|
|
3147
|
+
}
|
|
3148
|
+
/**
|
|
3149
|
+
* User-abort path that drains the queue, aborts the active run (and any in-flight retry),
|
|
3150
|
+
* waits for settle, then re-fires queued messages as a single fresh prompt.
|
|
3151
|
+
*
|
|
3152
|
+
* Behavior contract:
|
|
3153
|
+
* - clearAllQueues() is called synchronously so the pending-messages display empties immediately.
|
|
3154
|
+
* - `await session.abort()` ensures the previous run is fully idle before the fresh prompt fires,
|
|
3155
|
+
* so it starts a new turn instead of being re-queued as steering behind the dying run.
|
|
3156
|
+
* - When no messages were queued, the helper is just a sync clear + abort (no fresh prompt).
|
|
3157
|
+
* - Failures from the fresh prompt are surfaced via showError but do not throw.
|
|
3158
|
+
*/
|
|
3159
|
+
async abortAndFireQueuedMessages() {
|
|
3160
|
+
const { steering, followUp } = this.clearAllQueues();
|
|
3161
|
+
const allQueued = [...steering, ...followUp];
|
|
3162
|
+
this.updatePendingMessagesDisplay();
|
|
3163
|
+
await this.session.abort();
|
|
3164
|
+
if (allQueued.length === 0) {
|
|
3165
|
+
return 0;
|
|
3166
|
+
}
|
|
3167
|
+
const queuedText = allQueued.join("\n\n");
|
|
3168
|
+
try {
|
|
3169
|
+
await this.session.prompt(queuedText);
|
|
3170
|
+
}
|
|
3171
|
+
catch (error) {
|
|
3172
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
|
|
3173
|
+
this.showError(`Failed to fire queued message: ${errorMessage}`);
|
|
3035
3174
|
}
|
|
3036
3175
|
return allQueued.length;
|
|
3037
3176
|
}
|
|
@@ -3651,11 +3790,7 @@ export class InteractiveMode {
|
|
|
3651
3790
|
});
|
|
3652
3791
|
}
|
|
3653
3792
|
async handleResumeSession(sessionPath, options) {
|
|
3654
|
-
|
|
3655
|
-
this.loadingAnimation.stop();
|
|
3656
|
-
this.loadingAnimation = undefined;
|
|
3657
|
-
}
|
|
3658
|
-
this.statusContainer.clear();
|
|
3793
|
+
this.stopWorkingLoader();
|
|
3659
3794
|
try {
|
|
3660
3795
|
const result = await this.runtimeHost.switchSession(sessionPath, {
|
|
3661
3796
|
withSession: options?.withSession,
|
|
@@ -4140,11 +4275,7 @@ export class InteractiveMode {
|
|
|
4140
4275
|
return;
|
|
4141
4276
|
}
|
|
4142
4277
|
try {
|
|
4143
|
-
|
|
4144
|
-
this.loadingAnimation.stop();
|
|
4145
|
-
this.loadingAnimation = undefined;
|
|
4146
|
-
}
|
|
4147
|
-
this.statusContainer.clear();
|
|
4278
|
+
this.stopWorkingLoader();
|
|
4148
4279
|
const result = await this.runtimeHost.importFromJsonl(inputPath);
|
|
4149
4280
|
if (result.cancelled) {
|
|
4150
4281
|
this.showStatus("Import cancelled");
|
|
@@ -4299,32 +4430,7 @@ export class InteractiveMode {
|
|
|
4299
4430
|
handleSessionCommand() {
|
|
4300
4431
|
const stats = this.session.getSessionStats();
|
|
4301
4432
|
const sessionName = this.sessionManager.getSessionName();
|
|
4302
|
-
|
|
4303
|
-
if (sessionName) {
|
|
4304
|
-
info += `${theme.fg("dim", "Name:")} ${sessionName}\n`;
|
|
4305
|
-
}
|
|
4306
|
-
info += `${theme.fg("dim", "File:")} ${stats.sessionFile ?? "In-memory"}\n`;
|
|
4307
|
-
info += `${theme.fg("dim", "ID:")} ${stats.sessionId}\n\n`;
|
|
4308
|
-
info += `${theme.bold("Messages")}\n`;
|
|
4309
|
-
info += `${theme.fg("dim", "User:")} ${stats.userMessages}\n`;
|
|
4310
|
-
info += `${theme.fg("dim", "Assistant:")} ${stats.assistantMessages}\n`;
|
|
4311
|
-
info += `${theme.fg("dim", "Tool Calls:")} ${stats.toolCalls}\n`;
|
|
4312
|
-
info += `${theme.fg("dim", "Tool Results:")} ${stats.toolResults}\n`;
|
|
4313
|
-
info += `${theme.fg("dim", "Total:")} ${stats.totalMessages}\n\n`;
|
|
4314
|
-
info += `${theme.bold("Tokens")}\n`;
|
|
4315
|
-
info += `${theme.fg("dim", "Input:")} ${stats.tokens.input.toLocaleString()}\n`;
|
|
4316
|
-
info += `${theme.fg("dim", "Output:")} ${stats.tokens.output.toLocaleString()}\n`;
|
|
4317
|
-
if (stats.tokens.cacheRead > 0) {
|
|
4318
|
-
info += `${theme.fg("dim", "Cache Read:")} ${stats.tokens.cacheRead.toLocaleString()}\n`;
|
|
4319
|
-
}
|
|
4320
|
-
if (stats.tokens.cacheWrite > 0) {
|
|
4321
|
-
info += `${theme.fg("dim", "Cache Write:")} ${stats.tokens.cacheWrite.toLocaleString()}\n`;
|
|
4322
|
-
}
|
|
4323
|
-
info += `${theme.fg("dim", "Total:")} ${stats.tokens.total.toLocaleString()}\n`;
|
|
4324
|
-
if (stats.cost > 0) {
|
|
4325
|
-
info += `\n${theme.bold("Cost")}\n`;
|
|
4326
|
-
info += `${theme.fg("dim", "Total:")} ${stats.cost.toFixed(4)}`;
|
|
4327
|
-
}
|
|
4433
|
+
const info = formatSessionInfo(stats, sessionName);
|
|
4328
4434
|
this.chatContainer.addChild(new Spacer(1));
|
|
4329
4435
|
this.chatContainer.addChild(new Text(info, 1, 0));
|
|
4330
4436
|
this.ui.requestRender();
|
|
@@ -4468,11 +4574,7 @@ export class InteractiveMode {
|
|
|
4468
4574
|
this.ui.requestRender();
|
|
4469
4575
|
}
|
|
4470
4576
|
async handleClearCommand() {
|
|
4471
|
-
|
|
4472
|
-
this.loadingAnimation.stop();
|
|
4473
|
-
this.loadingAnimation = undefined;
|
|
4474
|
-
}
|
|
4475
|
-
this.statusContainer.clear();
|
|
4577
|
+
this.stopWorkingLoader();
|
|
4476
4578
|
try {
|
|
4477
4579
|
const result = await this.runtimeHost.newSession();
|
|
4478
4580
|
if (result.cancelled) {
|
|
@@ -4606,11 +4708,7 @@ export class InteractiveMode {
|
|
|
4606
4708
|
this.showWarning("Nothing to compact (no messages yet)");
|
|
4607
4709
|
return;
|
|
4608
4710
|
}
|
|
4609
|
-
|
|
4610
|
-
this.loadingAnimation.stop();
|
|
4611
|
-
this.loadingAnimation = undefined;
|
|
4612
|
-
}
|
|
4613
|
-
this.statusContainer.clear();
|
|
4711
|
+
this.stopWorkingLoader();
|
|
4614
4712
|
try {
|
|
4615
4713
|
await this.session.compact(customInstructions);
|
|
4616
4714
|
}
|
|
@@ -4623,10 +4721,7 @@ export class InteractiveMode {
|
|
|
4623
4721
|
if (this.settingsManager.getShowTerminalProgress()) {
|
|
4624
4722
|
this.ui.terminal.setProgress(false);
|
|
4625
4723
|
}
|
|
4626
|
-
|
|
4627
|
-
this.loadingAnimation.stop();
|
|
4628
|
-
this.loadingAnimation = undefined;
|
|
4629
|
-
}
|
|
4724
|
+
this.stopWorkingLoader();
|
|
4630
4725
|
this.clearExtensionTerminalInputListeners();
|
|
4631
4726
|
this.footer.dispose();
|
|
4632
4727
|
this.footerDataProvider.dispose();
|