dexto 1.5.3 → 1.5.4
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/dist/agents/coding-agent/coding-agent.yml +16 -0
- package/dist/cli/cli-subscriber.d.ts +4 -1
- package/dist/cli/cli-subscriber.d.ts.map +1 -1
- package/dist/cli/cli-subscriber.js +31 -1
- package/dist/cli/commands/interactive-commands/commands.d.ts.map +1 -1
- package/dist/cli/commands/interactive-commands/commands.js +2 -1
- package/dist/cli/commands/interactive-commands/general-commands.d.ts.map +1 -1
- package/dist/cli/commands/interactive-commands/general-commands.js +160 -3
- package/dist/cli/commands/interactive-commands/session/index.d.ts +2 -1
- package/dist/cli/commands/interactive-commands/session/index.d.ts.map +1 -1
- package/dist/cli/commands/interactive-commands/session/index.js +2 -1
- package/dist/cli/commands/interactive-commands/session/session-commands.d.ts +7 -0
- package/dist/cli/commands/interactive-commands/session/session-commands.d.ts.map +1 -1
- package/dist/cli/commands/interactive-commands/session/session-commands.js +16 -0
- package/dist/cli/ink-cli/InkCLIRefactored.d.ts +3 -1
- package/dist/cli/ink-cli/InkCLIRefactored.d.ts.map +1 -1
- package/dist/cli/ink-cli/InkCLIRefactored.js +36 -7
- package/dist/cli/ink-cli/components/StatusBar.d.ts +2 -1
- package/dist/cli/ink-cli/components/StatusBar.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/StatusBar.js +12 -3
- package/dist/cli/ink-cli/components/chat/MessageItem.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/chat/MessageItem.js +14 -3
- package/dist/cli/ink-cli/components/modes/AlternateBufferCLI.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/modes/AlternateBufferCLI.js +1 -1
- package/dist/cli/ink-cli/components/modes/StaticCLI.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/modes/StaticCLI.js +1 -1
- package/dist/cli/ink-cli/components/overlays/ContextStatsOverlay.d.ts +26 -0
- package/dist/cli/ink-cli/components/overlays/ContextStatsOverlay.d.ts.map +1 -0
- package/dist/cli/ink-cli/components/overlays/ContextStatsOverlay.js +240 -0
- package/dist/cli/ink-cli/components/overlays/SessionRenameOverlay.d.ts +21 -0
- package/dist/cli/ink-cli/components/overlays/SessionRenameOverlay.d.ts.map +1 -0
- package/dist/cli/ink-cli/components/overlays/SessionRenameOverlay.js +63 -0
- package/dist/cli/ink-cli/components/overlays/SessionSelectorRefactored.js +2 -2
- package/dist/cli/ink-cli/components/shared/MarkdownText.js +2 -2
- package/dist/cli/ink-cli/constants/processingPhrases.d.ts.map +1 -1
- package/dist/cli/ink-cli/constants/processingPhrases.js +14 -3
- package/dist/cli/ink-cli/constants/tips.d.ts.map +1 -1
- package/dist/cli/ink-cli/constants/tips.js +2 -0
- package/dist/cli/ink-cli/containers/InputContainer.d.ts.map +1 -1
- package/dist/cli/ink-cli/containers/InputContainer.js +8 -0
- package/dist/cli/ink-cli/containers/OverlayContainer.d.ts.map +1 -1
- package/dist/cli/ink-cli/containers/OverlayContainer.js +53 -2
- package/dist/cli/ink-cli/contexts/SoundContext.d.ts +23 -0
- package/dist/cli/ink-cli/contexts/SoundContext.d.ts.map +1 -0
- package/dist/cli/ink-cli/contexts/SoundContext.js +22 -0
- package/dist/cli/ink-cli/contexts/index.d.ts +1 -0
- package/dist/cli/ink-cli/contexts/index.d.ts.map +1 -1
- package/dist/cli/ink-cli/contexts/index.js +1 -0
- package/dist/cli/ink-cli/hooks/useCLIState.d.ts.map +1 -1
- package/dist/cli/ink-cli/hooks/useCLIState.js +1 -0
- package/dist/cli/ink-cli/services/processStream.d.ts +4 -0
- package/dist/cli/ink-cli/services/processStream.d.ts.map +1 -1
- package/dist/cli/ink-cli/services/processStream.js +76 -2
- package/dist/cli/ink-cli/state/initialState.d.ts.map +1 -1
- package/dist/cli/ink-cli/state/initialState.js +1 -0
- package/dist/cli/ink-cli/state/types.d.ts +8 -1
- package/dist/cli/ink-cli/state/types.d.ts.map +1 -1
- package/dist/cli/ink-cli/utils/commandOverlays.d.ts.map +1 -1
- package/dist/cli/ink-cli/utils/commandOverlays.js +4 -0
- package/dist/cli/ink-cli/utils/index.d.ts +1 -0
- package/dist/cli/ink-cli/utils/index.d.ts.map +1 -1
- package/dist/cli/ink-cli/utils/index.js +2 -0
- package/dist/cli/ink-cli/utils/messageFormatting.js +2 -2
- package/dist/cli/ink-cli/utils/soundNotification.d.ts +71 -0
- package/dist/cli/ink-cli/utils/soundNotification.d.ts.map +1 -0
- package/dist/cli/ink-cli/utils/soundNotification.js +203 -0
- package/dist/index.js +5 -0
- package/dist/webui/assets/{index-SGm5dxhp.js → index-Bh2aB65S.js} +161 -161
- package/dist/webui/index.html +1 -1
- package/package.json +7 -7
|
@@ -8,6 +8,14 @@ image: '@dexto/image-local'
|
|
|
8
8
|
# System prompt configuration - defines the agent's behavior as a coding assistant
|
|
9
9
|
systemPrompt:
|
|
10
10
|
contributors:
|
|
11
|
+
- id: date
|
|
12
|
+
type: dynamic
|
|
13
|
+
priority: 10
|
|
14
|
+
source: date
|
|
15
|
+
- id: env
|
|
16
|
+
type: dynamic
|
|
17
|
+
priority: 15
|
|
18
|
+
source: env
|
|
11
19
|
- id: primary
|
|
12
20
|
type: static
|
|
13
21
|
priority: 0
|
|
@@ -103,6 +111,14 @@ toolConfirmation:
|
|
|
103
111
|
# alwaysDeny:
|
|
104
112
|
# - custom--process-tools--bash_exec--rm -rf* # Prevent recursive deletion
|
|
105
113
|
|
|
114
|
+
# Compaction configuration - automatically summarizes conversation when context is full
|
|
115
|
+
compaction:
|
|
116
|
+
type: reactive-overflow
|
|
117
|
+
enabled: true
|
|
118
|
+
# Uncomment to override model's context window (useful for testing or capping usage):
|
|
119
|
+
# maxContextTokens: 50000 # Cap at 50K tokens regardless of model's max
|
|
120
|
+
# thresholdPercent: 0.9 # Trigger at 90% of context window (leaves safety buffer)
|
|
121
|
+
|
|
106
122
|
# Elicitation configuration - required for ask_user tool
|
|
107
123
|
elicitation:
|
|
108
124
|
enabled: true
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
import { DextoAgent } from '@dexto/core';
|
|
9
9
|
import { EventSubscriber } from '@dexto/server';
|
|
10
10
|
import { AgentEventBus } from '@dexto/core';
|
|
11
|
-
import type { SanitizedToolResult } from '@dexto/core';
|
|
11
|
+
import type { SanitizedToolResult, AgentEventMap } from '@dexto/core';
|
|
12
12
|
/**
|
|
13
13
|
* Event subscriber for CLI headless mode
|
|
14
14
|
* Implements the standard EventSubscriber pattern used throughout the codebase
|
|
@@ -30,6 +30,9 @@ export declare class CLISubscriber implements EventSubscriber {
|
|
|
30
30
|
onResponse(text: string): void;
|
|
31
31
|
onError(error: Error): void;
|
|
32
32
|
onConversationReset(): void;
|
|
33
|
+
onContextCompacting(payload: AgentEventMap['context:compacting']): void;
|
|
34
|
+
onContextCompacted(payload: AgentEventMap['context:compacted']): void;
|
|
35
|
+
onSessionContinued(payload: AgentEventMap['session:continued']): void;
|
|
33
36
|
/**
|
|
34
37
|
* Capture LLM token usage analytics
|
|
35
38
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli-subscriber.d.ts","sourceRoot":"","sources":["../../src/cli/cli-subscriber.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAU,UAAU,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,KAAK,EAAE,mBAAmB,
|
|
1
|
+
{"version":3,"file":"cli-subscriber.d.ts","sourceRoot":"","sources":["../../src/cli/cli-subscriber.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAU,UAAU,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,KAAK,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAGtE;;;GAGG;AACH,qBAAa,aAAc,YAAW,eAAe;IACjD,OAAO,CAAC,gBAAgB,CAAc;IACtC,OAAO,CAAC,iBAAiB,CAAC,CAAa;IACvC,OAAO,CAAC,gBAAgB,CAAC,CAAyB;IAElD,SAAS,CAAC,QAAQ,EAAE,aAAa,GAAG,IAAI;IAgCxC;;;OAGG;IACH,OAAO,IAAI,IAAI;IAcf,UAAU,IAAI,IAAI;IAIlB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAM3B,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,GAAG,IAAI;IAK9C,YAAY,CACR,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,mBAAmB,EAC9B,SAAS,CAAC,EAAE,OAAO,EACnB,OAAO,CAAC,EAAE,OAAO,GAClB,IAAI;IAMP,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IA0B9B,OAAO,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;IAyC3B,mBAAmB,IAAI,IAAI;IAM3B,mBAAmB,CAAC,OAAO,EAAE,aAAa,CAAC,oBAAoB,CAAC,GAAG,IAAI;IAOvE,kBAAkB,CAAC,OAAO,EAAE,aAAa,CAAC,mBAAmB,CAAC,GAAG,IAAI;IAcrE,kBAAkB,CAAC,OAAO,EAAE,aAAa,CAAC,mBAAmB,CAAC,GAAG,IAAI;IAWrE;;OAEG;IACH,OAAO,CAAC,iBAAiB;IA6BzB;;;OAGG;IACG,UAAU,CAAC,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAsBxF"}
|
|
@@ -37,6 +37,9 @@ export class CLISubscriber {
|
|
|
37
37
|
});
|
|
38
38
|
eventBus.on('llm:error', (payload) => this.onError(payload.error));
|
|
39
39
|
eventBus.on('session:reset', this.onConversationReset.bind(this));
|
|
40
|
+
eventBus.on('context:compacting', this.onContextCompacting.bind(this));
|
|
41
|
+
eventBus.on('context:compacted', this.onContextCompacted.bind(this));
|
|
42
|
+
eventBus.on('session:continued', this.onSessionContinued.bind(this));
|
|
40
43
|
}
|
|
41
44
|
/**
|
|
42
45
|
* Clean up internal state
|
|
@@ -134,14 +137,39 @@ export class CLISubscriber {
|
|
|
134
137
|
this.streamingContent = '';
|
|
135
138
|
logger.info('🔄 Conversation history cleared.', null, 'blue');
|
|
136
139
|
}
|
|
140
|
+
onContextCompacting(payload) {
|
|
141
|
+
// Output to stderr (doesn't interfere with stdout response stream)
|
|
142
|
+
process.stderr.write(`[📦 Compacting context (~${payload.estimatedTokens.toLocaleString()} tokens)...]\n`);
|
|
143
|
+
}
|
|
144
|
+
onContextCompacted(payload) {
|
|
145
|
+
const { originalTokens, compactedTokens, originalMessages, compactedMessages, reason } = payload;
|
|
146
|
+
const reductionPercent = originalTokens > 0
|
|
147
|
+
? Math.round(((originalTokens - compactedTokens) / originalTokens) * 100)
|
|
148
|
+
: 0;
|
|
149
|
+
// Output to stderr (doesn't interfere with stdout response stream)
|
|
150
|
+
process.stderr.write(`[📦 Context compacted (${reason}): ${originalTokens.toLocaleString()} → ~${compactedTokens.toLocaleString()} tokens (${reductionPercent}% reduction), ${originalMessages} → ${compactedMessages} messages]\n`);
|
|
151
|
+
}
|
|
152
|
+
onSessionContinued(payload) {
|
|
153
|
+
const { previousSessionId, newSessionId, summaryTokens, originalMessages, reason } = payload;
|
|
154
|
+
// Output to stderr (doesn't interfere with stdout response stream)
|
|
155
|
+
process.stderr.write(`[📦 Context compacted → Continuing in new session\n` +
|
|
156
|
+
` ${previousSessionId.slice(0, 8)}... → ${newSessionId.slice(0, 8)}...\n` +
|
|
157
|
+
` ${originalMessages} messages → ~${summaryTokens.toLocaleString()} token summary (${reason})]\n`);
|
|
158
|
+
}
|
|
137
159
|
/**
|
|
138
160
|
* Capture LLM token usage analytics
|
|
139
161
|
*/
|
|
140
162
|
captureTokenUsage(payload) {
|
|
141
|
-
const { tokenUsage, provider, model, sessionId } = payload;
|
|
163
|
+
const { tokenUsage, provider, model, sessionId, estimatedInputTokens } = payload;
|
|
142
164
|
if (!tokenUsage || (!tokenUsage.inputTokens && !tokenUsage.outputTokens)) {
|
|
143
165
|
return;
|
|
144
166
|
}
|
|
167
|
+
// Calculate estimate accuracy if both estimate and actual are available
|
|
168
|
+
let estimateAccuracyPercent;
|
|
169
|
+
if (estimatedInputTokens !== undefined && tokenUsage.inputTokens) {
|
|
170
|
+
const diff = estimatedInputTokens - tokenUsage.inputTokens;
|
|
171
|
+
estimateAccuracyPercent = Math.round((diff / tokenUsage.inputTokens) * 100);
|
|
172
|
+
}
|
|
145
173
|
capture('dexto_llm_tokens_consumed', {
|
|
146
174
|
source: 'cli',
|
|
147
175
|
sessionId,
|
|
@@ -153,6 +181,8 @@ export class CLISubscriber {
|
|
|
153
181
|
totalTokens: tokenUsage.totalTokens,
|
|
154
182
|
cacheReadTokens: tokenUsage.cacheReadTokens,
|
|
155
183
|
cacheWriteTokens: tokenUsage.cacheWriteTokens,
|
|
184
|
+
estimatedInputTokens,
|
|
185
|
+
estimateAccuracyPercent,
|
|
156
186
|
});
|
|
157
187
|
}
|
|
158
188
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/interactive-commands/commands.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,KAAK,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAYnF;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,YAAY,EAAE,iBAAiB,EAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/interactive-commands/commands.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,KAAK,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAYnF;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,YAAY,EAAE,iBAAiB,EAAO,CAAC;AAsCpD;;;;;GAKG;AACH,wBAAsB,cAAc,CAChC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,EACd,KAAK,EAAE,UAAU,EACjB,SAAS,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,oBAAoB,CAAC,CAyD/B;AAED;;;GAGG;AACH,wBAAgB,cAAc,IAAI,iBAAiB,EAAE,CAEpD"}
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
*/
|
|
21
21
|
// Import modular command definitions
|
|
22
22
|
import { generalCommands, createHelpCommand } from './general-commands.js';
|
|
23
|
-
import { searchCommand, resumeCommand } from './session/index.js';
|
|
23
|
+
import { searchCommand, resumeCommand, renameCommand } from './session/index.js';
|
|
24
24
|
import { modelCommands } from './model/index.js';
|
|
25
25
|
import { mcpCommands } from './mcp/index.js';
|
|
26
26
|
import { systemCommands } from './system/index.js';
|
|
@@ -51,6 +51,7 @@ const baseCommands = [
|
|
|
51
51
|
// Session management
|
|
52
52
|
searchCommand, // /search - opens search overlay
|
|
53
53
|
resumeCommand, // /resume - opens session selector overlay
|
|
54
|
+
renameCommand, // /rename <title> - rename current session
|
|
54
55
|
// Model management
|
|
55
56
|
modelCommands, // /model - opens model selector overlay
|
|
56
57
|
// MCP server management
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"general-commands.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/interactive-commands/general-commands.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAKH,OAAO,KAAK,EAAE,iBAAiB,EAAwC,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"general-commands.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/interactive-commands/general-commands.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAKH,OAAO,KAAK,EAAE,iBAAiB,EAAwC,MAAM,qBAAqB,CAAC;AAgGnG;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,cAAc,EAAE,MAAM,iBAAiB,EAAE,GAAG,iBAAiB,CAgC9F;AAED;;;GAGG;AACH,eAAO,MAAM,eAAe,EAAE,iBAAiB,EA8X9C,CAAC"}
|
|
@@ -15,17 +15,57 @@ import { formatForInkCli } from './utils/format-output.js';
|
|
|
15
15
|
import { CommandOutputHelper } from './utils/command-output.js';
|
|
16
16
|
import { writeToClipboard } from '../../ink-cli/utils/clipboardUtils.js';
|
|
17
17
|
/**
|
|
18
|
-
*
|
|
18
|
+
* Get the shell rc file path for the given shell
|
|
19
19
|
*/
|
|
20
|
+
function getShellRcFile(shell) {
|
|
21
|
+
const home = process.env.HOME;
|
|
22
|
+
if (!home)
|
|
23
|
+
return null;
|
|
24
|
+
if (shell.includes('zsh')) {
|
|
25
|
+
return `${home}/.zshrc`;
|
|
26
|
+
}
|
|
27
|
+
else if (shell.includes('bash')) {
|
|
28
|
+
return `${home}/.bashrc`;
|
|
29
|
+
}
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Wrap command to source shell rc file for alias support
|
|
34
|
+
* This mimics how Claude Code handles shell aliases - by sourcing the rc file
|
|
35
|
+
* before executing the command, we get aliases without using -i flag.
|
|
36
|
+
* We use eval to force the command to be re-parsed after sourcing, since
|
|
37
|
+
* aliases are expanded at parse time, not execution time.
|
|
38
|
+
*/
|
|
39
|
+
function wrapCommandWithRcSource(command, shell) {
|
|
40
|
+
const rcFile = getShellRcFile(shell);
|
|
41
|
+
if (!rcFile) {
|
|
42
|
+
return command;
|
|
43
|
+
}
|
|
44
|
+
// Escape single quotes in the command for safe eval
|
|
45
|
+
const escapedCommand = command.replace(/'/g, "'\\''");
|
|
46
|
+
// Source the rc file (suppressing errors if it doesn't exist), then eval the command
|
|
47
|
+
// eval forces re-parsing after sourcing, allowing aliases to expand
|
|
48
|
+
// For bash, we also need to enable expand_aliases
|
|
49
|
+
if (shell.includes('bash')) {
|
|
50
|
+
return `source "${rcFile}" 2>/dev/null; shopt -s expand_aliases 2>/dev/null; eval '${escapedCommand}'`;
|
|
51
|
+
}
|
|
52
|
+
return `source "${rcFile}" 2>/dev/null; eval '${escapedCommand}'`;
|
|
53
|
+
}
|
|
20
54
|
async function executeShellCommand(command, cwd, timeoutMs = 30000) {
|
|
21
55
|
return new Promise((resolve) => {
|
|
22
56
|
// Use user's default shell from SHELL env var, fallback to /bin/sh
|
|
23
|
-
//
|
|
57
|
+
// Avoid -i (interactive) as it sets up job control which causes SIGTTIN
|
|
58
|
+
// when the parent process tries to read stdin while shell runs.
|
|
59
|
+
// Instead, source the shell's rc file to get aliases (similar to Claude Code).
|
|
60
|
+
// Use detached: true to create a new process group, preventing the child
|
|
61
|
+
// from interfering with the parent's terminal control.
|
|
24
62
|
const userShell = process.env.SHELL || '/bin/sh';
|
|
25
|
-
const
|
|
63
|
+
const wrappedCommand = wrapCommandWithRcSource(command, userShell);
|
|
64
|
+
const child = spawn(userShell, ['-c', wrappedCommand], {
|
|
26
65
|
cwd,
|
|
27
66
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
28
67
|
env: { ...process.env },
|
|
68
|
+
detached: true,
|
|
29
69
|
});
|
|
30
70
|
let stdout = '';
|
|
31
71
|
let stderr = '';
|
|
@@ -148,6 +188,123 @@ export const generalCommands = [
|
|
|
148
188
|
}
|
|
149
189
|
},
|
|
150
190
|
},
|
|
191
|
+
{
|
|
192
|
+
name: 'compact',
|
|
193
|
+
description: 'Compact context by summarizing older messages',
|
|
194
|
+
usage: '/compact',
|
|
195
|
+
category: 'General',
|
|
196
|
+
aliases: ['summarize'],
|
|
197
|
+
handler: async (_args, agent, ctx) => {
|
|
198
|
+
try {
|
|
199
|
+
const { sessionId } = ctx;
|
|
200
|
+
if (!sessionId) {
|
|
201
|
+
return formatForInkCli('⚠️ No active session to compact');
|
|
202
|
+
}
|
|
203
|
+
// Compact context - generates summary and hides older messages
|
|
204
|
+
const result = await agent.compactContext(sessionId);
|
|
205
|
+
if (!result) {
|
|
206
|
+
return formatForInkCli('💡 Nothing to compact - history is too short or compaction is not configured.');
|
|
207
|
+
}
|
|
208
|
+
return formatForInkCli(`📦 Context compacted → Continuing in new session\n` +
|
|
209
|
+
` ${result.previousSessionId.slice(0, 8)}... → ${result.newSessionId.slice(0, 8)}...\n` +
|
|
210
|
+
` ${result.originalMessages} messages → ~${result.summaryTokens.toLocaleString()} token summary\n` +
|
|
211
|
+
`💡 New session created with conversation summary. Old session preserved.`);
|
|
212
|
+
}
|
|
213
|
+
catch (error) {
|
|
214
|
+
const errorMsg = `Failed to compact context: ${error instanceof Error ? error.message : String(error)}`;
|
|
215
|
+
agent.logger.error(errorMsg);
|
|
216
|
+
return formatForInkCli(`❌ ${errorMsg}`);
|
|
217
|
+
}
|
|
218
|
+
},
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
name: 'context',
|
|
222
|
+
description: 'Show context window usage statistics',
|
|
223
|
+
usage: '/context',
|
|
224
|
+
category: 'General',
|
|
225
|
+
aliases: ['ctx', 'tokens'],
|
|
226
|
+
handler: async (_args, agent, ctx) => {
|
|
227
|
+
try {
|
|
228
|
+
const { sessionId } = ctx;
|
|
229
|
+
if (!sessionId) {
|
|
230
|
+
return formatForInkCli('⚠️ No active session');
|
|
231
|
+
}
|
|
232
|
+
const stats = await agent.getContextStats(sessionId);
|
|
233
|
+
// Create a visual progress bar (clamped to 0-100% for display)
|
|
234
|
+
const barWidth = 20;
|
|
235
|
+
const displayPercent = Math.min(Math.max(stats.usagePercent, 0), 100);
|
|
236
|
+
const filledWidth = Math.round((displayPercent / 100) * barWidth);
|
|
237
|
+
const emptyWidth = barWidth - filledWidth;
|
|
238
|
+
const progressBar = '█'.repeat(filledWidth) + '░'.repeat(emptyWidth);
|
|
239
|
+
// Color based on usage
|
|
240
|
+
let usageColor = chalk.green;
|
|
241
|
+
if (stats.usagePercent > 80)
|
|
242
|
+
usageColor = chalk.red;
|
|
243
|
+
else if (stats.usagePercent > 60)
|
|
244
|
+
usageColor = chalk.yellow;
|
|
245
|
+
// Helper to format token counts
|
|
246
|
+
const formatTokens = (tokens) => {
|
|
247
|
+
if (tokens >= 1000) {
|
|
248
|
+
return `${(tokens / 1000).toFixed(1)}k`;
|
|
249
|
+
}
|
|
250
|
+
return tokens.toLocaleString();
|
|
251
|
+
};
|
|
252
|
+
// Helper to calculate percentage of max
|
|
253
|
+
const pct = (tokens) => {
|
|
254
|
+
const percent = stats.maxContextTokens > 0
|
|
255
|
+
? ((tokens / stats.maxContextTokens) * 100).toFixed(1)
|
|
256
|
+
: '0.0';
|
|
257
|
+
return `${percent}%`;
|
|
258
|
+
};
|
|
259
|
+
const overflowWarning = stats.usagePercent > 100 ? ' ⚠️ OVERFLOW' : '';
|
|
260
|
+
const { breakdown } = stats;
|
|
261
|
+
// Show actual tokens if available, otherwise estimate with indicator
|
|
262
|
+
const tokenDisplay = stats.actualTokens !== null
|
|
263
|
+
? `${formatTokens(stats.actualTokens)}`
|
|
264
|
+
: `~${formatTokens(stats.estimatedTokens)}`;
|
|
265
|
+
// Calculate auto compact buffer (reserved space before compaction triggers)
|
|
266
|
+
// maxContextTokens already has thresholdPercent applied, so we need to derive
|
|
267
|
+
// the buffer as: maxContextTokens * (1 - thresholdPercent) / thresholdPercent
|
|
268
|
+
const autoCompactBuffer = stats.thresholdPercent > 0 && stats.thresholdPercent < 1.0
|
|
269
|
+
? Math.floor((stats.maxContextTokens * (1 - stats.thresholdPercent)) /
|
|
270
|
+
stats.thresholdPercent)
|
|
271
|
+
: 0;
|
|
272
|
+
const bufferPercent = Math.round((1 - stats.thresholdPercent) * 100);
|
|
273
|
+
const bufferLabel = bufferPercent > 0
|
|
274
|
+
? `Auto compact buffer (${bufferPercent}%)`
|
|
275
|
+
: 'Auto compact buffer';
|
|
276
|
+
const lines = [
|
|
277
|
+
`📊 Context Usage`,
|
|
278
|
+
` ${usageColor(progressBar)} ${stats.usagePercent}%${overflowWarning}`,
|
|
279
|
+
` ${chalk.dim(stats.modelDisplayName)} · ${tokenDisplay} / ${formatTokens(stats.maxContextTokens)} tokens`,
|
|
280
|
+
``,
|
|
281
|
+
` ${chalk.cyan('Breakdown:')} ${stats.actualTokens === null ? chalk.dim('(estimated)') : ''}`,
|
|
282
|
+
` ├─ System prompt: ${formatTokens(breakdown.systemPrompt)} (${pct(breakdown.systemPrompt)})`,
|
|
283
|
+
` ├─ Tools: ${formatTokens(breakdown.tools.total)} (${pct(breakdown.tools.total)})`,
|
|
284
|
+
` ├─ Messages: ${formatTokens(breakdown.messages)} (${pct(breakdown.messages)})`,
|
|
285
|
+
` └─ ${bufferLabel}: ${formatTokens(autoCompactBuffer)} (reserved)`,
|
|
286
|
+
``,
|
|
287
|
+
` Messages: ${stats.filteredMessageCount} visible (${stats.messageCount} total)`,
|
|
288
|
+
];
|
|
289
|
+
// Show pruned tool count if any
|
|
290
|
+
if (stats.prunedToolCount > 0) {
|
|
291
|
+
lines.push(` 🗑️ ${stats.prunedToolCount} tool output(s) pruned`);
|
|
292
|
+
}
|
|
293
|
+
if (stats.hasSummary) {
|
|
294
|
+
lines.push(` 📦 Context has been compacted`);
|
|
295
|
+
}
|
|
296
|
+
if (stats.usagePercent > 100) {
|
|
297
|
+
lines.push(` 💡 Use /compact to manually compact, or send a message to trigger auto-compaction`);
|
|
298
|
+
}
|
|
299
|
+
return formatForInkCli(lines.join('\n'));
|
|
300
|
+
}
|
|
301
|
+
catch (error) {
|
|
302
|
+
const errorMsg = `Failed to get context stats: ${error instanceof Error ? error.message : String(error)}`;
|
|
303
|
+
agent.logger.error(errorMsg);
|
|
304
|
+
return formatForInkCli(`❌ ${errorMsg}`);
|
|
305
|
+
}
|
|
306
|
+
},
|
|
307
|
+
},
|
|
151
308
|
{
|
|
152
309
|
name: 'copy',
|
|
153
310
|
description: 'Copy the last assistant response to clipboard',
|
|
@@ -7,8 +7,9 @@
|
|
|
7
7
|
* Exports:
|
|
8
8
|
* - searchCommand: Opens interactive search overlay
|
|
9
9
|
* - resumeCommand: Shows interactive session selector
|
|
10
|
+
* - renameCommand: Rename the current session
|
|
10
11
|
*
|
|
11
12
|
* Note: For headless CLI session management, see src/cli/commands/session-commands.ts
|
|
12
13
|
*/
|
|
13
|
-
export { searchCommand, resumeCommand } from './session-commands.js';
|
|
14
|
+
export { searchCommand, resumeCommand, renameCommand } from './session-commands.js';
|
|
14
15
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/cli/commands/interactive-commands/session/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/cli/commands/interactive-commands/session/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC"}
|
|
@@ -7,7 +7,8 @@
|
|
|
7
7
|
* Exports:
|
|
8
8
|
* - searchCommand: Opens interactive search overlay
|
|
9
9
|
* - resumeCommand: Shows interactive session selector
|
|
10
|
+
* - renameCommand: Rename the current session
|
|
10
11
|
*
|
|
11
12
|
* Note: For headless CLI session management, see src/cli/commands/session-commands.ts
|
|
12
13
|
*/
|
|
13
|
-
export { searchCommand, resumeCommand } from './session-commands.js';
|
|
14
|
+
export { searchCommand, resumeCommand, renameCommand } from './session-commands.js';
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* Commands:
|
|
8
8
|
* - resume: Shows interactive session selector
|
|
9
9
|
* - search: Opens interactive search overlay
|
|
10
|
+
* - rename: Rename the current session
|
|
10
11
|
*
|
|
11
12
|
* Note: For headless CLI session management (list, history, delete),
|
|
12
13
|
* see src/cli/commands/session-commands.ts
|
|
@@ -22,4 +23,10 @@ export declare const resumeCommand: CommandDefinition;
|
|
|
22
23
|
* Standalone search command - opens interactive search overlay
|
|
23
24
|
*/
|
|
24
25
|
export declare const searchCommand: CommandDefinition;
|
|
26
|
+
/**
|
|
27
|
+
* Rename command - rename the current session
|
|
28
|
+
* In interactive CLI, this shows the rename overlay.
|
|
29
|
+
* The overlay is triggered via commandOverlays.ts registry.
|
|
30
|
+
*/
|
|
31
|
+
export declare const renameCommand: CommandDefinition;
|
|
25
32
|
//# sourceMappingURL=session-commands.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-commands.d.ts","sourceRoot":"","sources":["../../../../../src/cli/commands/interactive-commands/session/session-commands.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"session-commands.d.ts","sourceRoot":"","sources":["../../../../../src/cli/commands/interactive-commands/session/session-commands.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAIH,OAAO,KAAK,EAAE,iBAAiB,EAAkB,MAAM,sBAAsB,CAAC;AAE9E;;;;GAIG;AACH,eAAO,MAAM,aAAa,EAAE,iBAsB3B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,aAAa,EAAE,iBAc3B,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,aAAa,EAAE,iBAa3B,CAAC"}
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* Commands:
|
|
8
8
|
* - resume: Shows interactive session selector
|
|
9
9
|
* - search: Opens interactive search overlay
|
|
10
|
+
* - rename: Rename the current session
|
|
10
11
|
*
|
|
11
12
|
* Note: For headless CLI session management (list, history, delete),
|
|
12
13
|
* see src/cli/commands/session-commands.ts
|
|
@@ -49,3 +50,18 @@ export const searchCommand = {
|
|
|
49
50
|
return true;
|
|
50
51
|
},
|
|
51
52
|
};
|
|
53
|
+
/**
|
|
54
|
+
* Rename command - rename the current session
|
|
55
|
+
* In interactive CLI, this shows the rename overlay.
|
|
56
|
+
* The overlay is triggered via commandOverlays.ts registry.
|
|
57
|
+
*/
|
|
58
|
+
export const renameCommand = {
|
|
59
|
+
name: 'rename',
|
|
60
|
+
description: 'Rename the current session',
|
|
61
|
+
usage: '/rename',
|
|
62
|
+
category: 'General',
|
|
63
|
+
handler: async (_args, _agent, _ctx) => {
|
|
64
|
+
// Interactive overlay handles everything - just return success
|
|
65
|
+
return true;
|
|
66
|
+
},
|
|
67
|
+
};
|
|
@@ -9,10 +9,12 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import type { DextoAgent } from '@dexto/core';
|
|
11
11
|
import type { StartupInfo } from './state/types.js';
|
|
12
|
+
import type { SoundNotificationService } from './utils/soundNotification.js';
|
|
12
13
|
interface InkCLIProps {
|
|
13
14
|
agent: DextoAgent;
|
|
14
15
|
initialSessionId: string | null;
|
|
15
16
|
startupInfo: StartupInfo;
|
|
17
|
+
soundService: SoundNotificationService | null;
|
|
16
18
|
}
|
|
17
19
|
/**
|
|
18
20
|
* Modern CLI interface using React Ink
|
|
@@ -22,7 +24,7 @@ interface InkCLIProps {
|
|
|
22
24
|
* - KeypressProvider for unified keyboard input
|
|
23
25
|
* - MouseProvider (only in alternate buffer mode)
|
|
24
26
|
*/
|
|
25
|
-
export declare function InkCLIRefactored({ agent, initialSessionId, startupInfo }: InkCLIProps): import("react/jsx-runtime").JSX.Element;
|
|
27
|
+
export declare function InkCLIRefactored({ agent, initialSessionId, startupInfo, soundService, }: InkCLIProps): import("react/jsx-runtime").JSX.Element;
|
|
26
28
|
/**
|
|
27
29
|
* Start the modern Ink-based CLI
|
|
28
30
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InkCLIRefactored.d.ts","sourceRoot":"","sources":["../../../src/cli/ink-cli/InkCLIRefactored.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAK9C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"InkCLIRefactored.d.ts","sourceRoot":"","sources":["../../../src/cli/ink-cli/InkCLIRefactored.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAK9C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAWpD,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,8BAA8B,CAAC;AAiB7E,UAAU,WAAW;IACjB,KAAK,EAAE,UAAU,CAAC;IAClB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,WAAW,EAAE,WAAW,CAAC;IACzB,YAAY,EAAE,wBAAwB,GAAG,IAAI,CAAC;CACjD;AA6CD;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,EAC7B,KAAK,EACL,gBAAgB,EAChB,WAAW,EACX,YAAY,GACf,EAAE,WAAW,2CAgBb;AAED;;GAEG;AACH,wBAAsB,qBAAqB,CACvC,KAAK,EAAE,UAAU,EACjB,gBAAgB,EAAE,MAAM,GAAG,IAAI,GAChC,OAAO,CAAC,IAAI,CAAC,CAgEf"}
|
|
@@ -13,7 +13,7 @@ import { render } from 'ink';
|
|
|
13
13
|
import { registerGracefulShutdown } from '../../utils/graceful-shutdown.js';
|
|
14
14
|
import { enableBracketedPaste, disableBracketedPaste } from './utils/bracketedPaste.js';
|
|
15
15
|
// Contexts (keyboard/mouse providers)
|
|
16
|
-
import { KeypressProvider, MouseProvider, ScrollProvider } from './contexts/index.js';
|
|
16
|
+
import { KeypressProvider, MouseProvider, ScrollProvider, SoundProvider, } from './contexts/index.js';
|
|
17
17
|
// Components
|
|
18
18
|
import { ErrorBoundary } from './components/ErrorBoundary.js';
|
|
19
19
|
import { AlternateBufferCLI, StaticCLI } from './components/modes/index.js';
|
|
@@ -28,7 +28,7 @@ const USE_ALTERNATE_BUFFER = false;
|
|
|
28
28
|
/**
|
|
29
29
|
* Inner component that wraps the mode-specific component with providers
|
|
30
30
|
*/
|
|
31
|
-
function InkCLIInner({ agent, initialSessionId, startupInfo }) {
|
|
31
|
+
function InkCLIInner({ agent, initialSessionId, startupInfo, soundService }) {
|
|
32
32
|
// Selection hint callback for alternate buffer mode
|
|
33
33
|
const [, setSelectionHintShown] = useState(false);
|
|
34
34
|
// Streaming mode - can be toggled via /stream command
|
|
@@ -37,10 +37,10 @@ function InkCLIInner({ agent, initialSessionId, startupInfo }) {
|
|
|
37
37
|
setSelectionHintShown(true);
|
|
38
38
|
}, []);
|
|
39
39
|
if (USE_ALTERNATE_BUFFER) {
|
|
40
|
-
return (_jsx(ScrollProvider, { onSelectionAttempt: handleSelectionAttempt, children: _jsx(AlternateBufferCLI, { agent: agent, initialSessionId: initialSessionId, startupInfo: startupInfo, onSelectionAttempt: handleSelectionAttempt, useStreaming: streaming }) }));
|
|
40
|
+
return (_jsx(SoundProvider, { soundService: soundService, children: _jsx(ScrollProvider, { onSelectionAttempt: handleSelectionAttempt, children: _jsx(AlternateBufferCLI, { agent: agent, initialSessionId: initialSessionId, startupInfo: startupInfo, onSelectionAttempt: handleSelectionAttempt, useStreaming: streaming }) }) }));
|
|
41
41
|
}
|
|
42
42
|
// Static mode - no ScrollProvider needed
|
|
43
|
-
return (_jsx(StaticCLI, { agent: agent, initialSessionId: initialSessionId, startupInfo: startupInfo, useStreaming: streaming }));
|
|
43
|
+
return (_jsx(SoundProvider, { soundService: soundService, children: _jsx(StaticCLI, { agent: agent, initialSessionId: initialSessionId, startupInfo: startupInfo, useStreaming: streaming }) }));
|
|
44
44
|
}
|
|
45
45
|
/**
|
|
46
46
|
* Modern CLI interface using React Ink
|
|
@@ -50,8 +50,8 @@ function InkCLIInner({ agent, initialSessionId, startupInfo }) {
|
|
|
50
50
|
* - KeypressProvider for unified keyboard input
|
|
51
51
|
* - MouseProvider (only in alternate buffer mode)
|
|
52
52
|
*/
|
|
53
|
-
export function InkCLIRefactored({ agent, initialSessionId, startupInfo }) {
|
|
54
|
-
return (_jsx(ErrorBoundary, { children: _jsx(KeypressProvider, { children: _jsx(MouseProvider, { mouseEventsEnabled: USE_ALTERNATE_BUFFER, children: _jsx(InkCLIInner, { agent: agent, initialSessionId: initialSessionId, startupInfo: startupInfo }) }) }) }));
|
|
53
|
+
export function InkCLIRefactored({ agent, initialSessionId, startupInfo, soundService, }) {
|
|
54
|
+
return (_jsx(ErrorBoundary, { children: _jsx(KeypressProvider, { children: _jsx(MouseProvider, { mouseEventsEnabled: USE_ALTERNATE_BUFFER, children: _jsx(InkCLIInner, { agent: agent, initialSessionId: initialSessionId, startupInfo: startupInfo, soundService: soundService }) }) }) }));
|
|
55
55
|
}
|
|
56
56
|
/**
|
|
57
57
|
* Start the modern Ink-based CLI
|
|
@@ -62,7 +62,36 @@ export async function startInkCliRefactored(agent, initialSessionId) {
|
|
|
62
62
|
// This wraps pastes with escape sequences that our KeypressContext handles
|
|
63
63
|
enableBracketedPaste();
|
|
64
64
|
const startupInfo = await getStartupInfo(agent);
|
|
65
|
-
|
|
65
|
+
// Initialize sound service from preferences
|
|
66
|
+
const { SoundNotificationService } = await import('./utils/soundNotification.js');
|
|
67
|
+
const { globalPreferencesExist, loadGlobalPreferences } = await import('@dexto/agent-management');
|
|
68
|
+
let soundService = null;
|
|
69
|
+
// Initialize sound config with defaults (enabled by default even without preferences file)
|
|
70
|
+
let soundConfig = {
|
|
71
|
+
enabled: true,
|
|
72
|
+
onApprovalRequired: true,
|
|
73
|
+
onTaskComplete: true,
|
|
74
|
+
};
|
|
75
|
+
// Override with user preferences if they exist
|
|
76
|
+
if (globalPreferencesExist()) {
|
|
77
|
+
try {
|
|
78
|
+
const preferences = await loadGlobalPreferences();
|
|
79
|
+
soundConfig = {
|
|
80
|
+
enabled: preferences.sounds?.enabled ?? soundConfig.enabled,
|
|
81
|
+
onApprovalRequired: preferences.sounds?.onApprovalRequired ?? soundConfig.onApprovalRequired,
|
|
82
|
+
onTaskComplete: preferences.sounds?.onTaskComplete ?? soundConfig.onTaskComplete,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
// Log at debug level to help troubleshoot sound configuration issues
|
|
87
|
+
// Continue with default sounds - this is non-critical functionality
|
|
88
|
+
agent.logger.debug(`Sound preferences could not be loaded: ${error instanceof Error ? error.message : String(error)}`);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
if (soundConfig.enabled) {
|
|
92
|
+
soundService = new SoundNotificationService(soundConfig);
|
|
93
|
+
}
|
|
94
|
+
const inkApp = render(_jsx(InkCLIRefactored, { agent: agent, initialSessionId: initialSessionId, startupInfo: startupInfo, soundService: soundService }), {
|
|
66
95
|
exitOnCtrlC: false,
|
|
67
96
|
alternateBuffer: USE_ALTERNATE_BUFFER,
|
|
68
97
|
// Incremental rendering works better with VirtualizedList
|
|
@@ -12,6 +12,7 @@ interface StatusBarProps {
|
|
|
12
12
|
agent: DextoAgent;
|
|
13
13
|
isProcessing: boolean;
|
|
14
14
|
isThinking: boolean;
|
|
15
|
+
isCompacting: boolean;
|
|
15
16
|
approvalQueueCount: number;
|
|
16
17
|
copyModeEnabled?: boolean;
|
|
17
18
|
/** Whether an approval prompt is currently shown */
|
|
@@ -25,6 +26,6 @@ interface StatusBarProps {
|
|
|
25
26
|
* - Hide spinner during approval wait (user is reviewing, not waiting)
|
|
26
27
|
* - Only show elapsed time after 30s (avoid visual noise for fast operations)
|
|
27
28
|
*/
|
|
28
|
-
export declare function StatusBar({ agent, isProcessing, isThinking, approvalQueueCount, copyModeEnabled, isAwaitingApproval, }: StatusBarProps): import("react/jsx-runtime").JSX.Element | null;
|
|
29
|
+
export declare function StatusBar({ agent, isProcessing, isThinking, isCompacting, approvalQueueCount, copyModeEnabled, isAwaitingApproval, }: StatusBarProps): import("react/jsx-runtime").JSX.Element | null;
|
|
29
30
|
export {};
|
|
30
31
|
//# sourceMappingURL=StatusBar.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StatusBar.d.ts","sourceRoot":"","sources":["../../../../src/cli/ink-cli/components/StatusBar.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAK9C,UAAU,cAAc;IACpB,KAAK,EAAE,UAAU,CAAC;IAClB,YAAY,EAAE,OAAO,CAAC;IACtB,UAAU,EAAE,OAAO,CAAC;IACpB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,oDAAoD;IACpD,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAChC;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,EACtB,KAAK,EACL,YAAY,EACZ,UAAU,EACV,kBAAkB,EAClB,eAAuB,EACvB,kBAA0B,GAC7B,EAAE,cAAc,
|
|
1
|
+
{"version":3,"file":"StatusBar.d.ts","sourceRoot":"","sources":["../../../../src/cli/ink-cli/components/StatusBar.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAK9C,UAAU,cAAc;IACpB,KAAK,EAAE,UAAU,CAAC;IAClB,YAAY,EAAE,OAAO,CAAC;IACtB,UAAU,EAAE,OAAO,CAAC;IACpB,YAAY,EAAE,OAAO,CAAC;IACtB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,oDAAoD;IACpD,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAChC;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,EACtB,KAAK,EACL,YAAY,EACZ,UAAU,EACV,YAAY,EACZ,kBAAkB,EAClB,eAAuB,EACvB,kBAA0B,GAC7B,EAAE,cAAc,kDA6GhB"}
|
|
@@ -21,9 +21,9 @@ import { useTokenCounter } from '../hooks/useTokenCounter.js';
|
|
|
21
21
|
* - Hide spinner during approval wait (user is reviewing, not waiting)
|
|
22
22
|
* - Only show elapsed time after 30s (avoid visual noise for fast operations)
|
|
23
23
|
*/
|
|
24
|
-
export function StatusBar({ agent, isProcessing, isThinking, approvalQueueCount, copyModeEnabled = false, isAwaitingApproval = false, }) {
|
|
25
|
-
// Cycle through witty phrases while processing
|
|
26
|
-
const { phrase } = usePhraseCycler({ isActive: isProcessing });
|
|
24
|
+
export function StatusBar({ agent, isProcessing, isThinking, isCompacting, approvalQueueCount, copyModeEnabled = false, isAwaitingApproval = false, }) {
|
|
25
|
+
// Cycle through witty phrases while processing (not during compacting)
|
|
26
|
+
const { phrase } = usePhraseCycler({ isActive: isProcessing && !isCompacting });
|
|
27
27
|
// Track elapsed time during processing
|
|
28
28
|
const { formatted: elapsedTime, elapsedMs } = useElapsedTime({ isActive: isProcessing });
|
|
29
29
|
// Track token usage during processing
|
|
@@ -42,6 +42,15 @@ export function StatusBar({ agent, isProcessing, isThinking, approvalQueueCount,
|
|
|
42
42
|
if (isAwaitingApproval) {
|
|
43
43
|
return null;
|
|
44
44
|
}
|
|
45
|
+
// Show compacting state - yellow/orange color to indicate context management
|
|
46
|
+
if (isCompacting) {
|
|
47
|
+
const metaParts = [];
|
|
48
|
+
if (showTime)
|
|
49
|
+
metaParts.push(`(${elapsedTime})`);
|
|
50
|
+
metaParts.push('Esc to cancel');
|
|
51
|
+
const metaContent = metaParts.join(' • ');
|
|
52
|
+
return (_jsxs(Box, { paddingX: 1, marginTop: 1, marginBottom: 1, flexDirection: "column", children: [_jsxs(Box, { flexDirection: "row", alignItems: "center", children: [_jsx(Text, { color: "yellow", children: _jsx(Spinner, { type: "dots" }) }), _jsx(Text, { color: "yellow", children: " \uD83D\uDCE6 Compacting context..." })] }), _jsx(Box, { marginLeft: 2, children: _jsx(Text, { color: "gray", children: metaContent }) })] }));
|
|
53
|
+
}
|
|
45
54
|
// Show initial processing state (before streaming starts) - green/teal color
|
|
46
55
|
// TODO: Rename this event/state to "reasoning" and associate it with actual reasoning tokens
|
|
47
56
|
// Currently "thinking" event fires before any response, not during reasoning token generation
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MessageItem.d.ts","sourceRoot":"","sources":["../../../../../src/cli/ink-cli/components/chat/MessageItem.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,KAAK,EACR,OAAO,EAUV,MAAM,sBAAsB,CAAC;AAuC9B,UAAU,gBAAgB;IACtB,OAAO,EAAE,OAAO,CAAC;IACjB,2DAA2D;IAC3D,aAAa,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;;;;;GAMG;AACH,eAAO,MAAM,WAAW,mEACc,gBAAgB,
|
|
1
|
+
{"version":3,"file":"MessageItem.d.ts","sourceRoot":"","sources":["../../../../../src/cli/ink-cli/components/chat/MessageItem.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,KAAK,EACR,OAAO,EAUV,MAAM,sBAAsB,CAAC;AAuC9B,UAAU,gBAAgB;IACtB,OAAO,EAAE,OAAO,CAAC;IACjB,2DAA2D;IAC3D,aAAa,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;;;;;GAMG;AACH,eAAO,MAAM,WAAW,mEACc,gBAAgB,6CA6NrD,CAAC"}
|
|
@@ -113,7 +113,13 @@ export const MessageItem = memo(({ message, terminalWidth = 80 }) => {
|
|
|
113
113
|
const toolArgs = parenIndex > 0 ? message.content.slice(parenIndex) : '';
|
|
114
114
|
// Build the full tool header text for wrapping
|
|
115
115
|
// Don't include status suffix if we have sub-agent progress (it shows its own status)
|
|
116
|
-
const statusSuffix = subAgentProgress
|
|
116
|
+
const statusSuffix = subAgentProgress
|
|
117
|
+
? ''
|
|
118
|
+
: isRunning
|
|
119
|
+
? ' Running...'
|
|
120
|
+
: isPending
|
|
121
|
+
? ' Waiting...'
|
|
122
|
+
: '';
|
|
117
123
|
const fullToolText = `${toolName}${toolArgs}${statusSuffix}`;
|
|
118
124
|
// ToolIcon takes 2 chars ("● "), so available width is terminalWidth - 2
|
|
119
125
|
const iconWidth = 2;
|
|
@@ -124,7 +130,10 @@ export const MessageItem = memo(({ message, terminalWidth = 80 }) => {
|
|
|
124
130
|
trim: false,
|
|
125
131
|
});
|
|
126
132
|
const toolLines = wrappedToolText.split('\n');
|
|
127
|
-
return (_jsxs(Box, { flexDirection: "column", marginTop: 1, width: terminalWidth, children: [toolLines.map((line, i) => (_jsxs(Box, { flexDirection: "row", children: [i === 0 ? (_jsx(ToolIcon, { status: message.toolStatus || 'finished', isError: message.isError ?? false })) : (_jsx(Text, { children: ' ' })), _jsx(Text, { children: i === 0 ? (_jsxs(_Fragment, { children: [_jsx(Text, { bold: true, children: line.slice(0, toolName.length) }), _jsx(Text, { children: line.slice(toolName.length) })] })) : (line) })] }, i))), subAgentProgress && isRunning && (_jsx(Box, { marginLeft: 2, children: _jsxs(Text, { color: "gray", children: ["\u2514\u2500 ", subAgentProgress.toolsCalled, " tool", subAgentProgress.toolsCalled !== 1 ? 's' : '', " called | Current:", ' ', subAgentProgress.currentTool
|
|
133
|
+
return (_jsxs(Box, { flexDirection: "column", marginTop: 1, width: terminalWidth, children: [toolLines.map((line, i) => (_jsxs(Box, { flexDirection: "row", children: [i === 0 ? (_jsx(ToolIcon, { status: message.toolStatus || 'finished', isError: message.isError ?? false })) : (_jsx(Text, { children: ' ' })), _jsx(Text, { children: i === 0 ? (_jsxs(_Fragment, { children: [_jsx(Text, { bold: true, children: line.slice(0, toolName.length) }), _jsx(Text, { children: line.slice(toolName.length) })] })) : (line) })] }, i))), subAgentProgress && isRunning && (_jsx(Box, { marginLeft: 2, children: _jsxs(Text, { color: "gray", children: ["\u2514\u2500 ", subAgentProgress.toolsCalled, " tool", subAgentProgress.toolsCalled !== 1 ? 's' : '', " called | Current:", ' ', subAgentProgress.currentTool, subAgentProgress.tokenUsage &&
|
|
134
|
+
subAgentProgress.tokenUsage.total > 0
|
|
135
|
+
? ` | ${subAgentProgress.tokenUsage.total.toLocaleString()} tokens`
|
|
136
|
+
: ''] }) })), hasStructuredDisplay ? (_jsx(ToolResultRenderer, { display: message.toolDisplayData, content: message.toolContent })) : (message.toolResult && (_jsx(Box, { flexDirection: "column", children: _jsxs(Text, { color: "gray", children: [" \u23BF ", message.toolResult] }) })))] }));
|
|
128
137
|
}
|
|
129
138
|
// System message: Compact gray text
|
|
130
139
|
return (_jsx(Box, { flexDirection: "column", marginBottom: 1, width: terminalWidth, children: _jsx(Text, { color: "gray", children: message.content }) }));
|
|
@@ -147,6 +156,8 @@ export const MessageItem = memo(({ message, terminalWidth = 80 }) => {
|
|
|
147
156
|
prev.message.subAgentProgress?.toolsCalled ===
|
|
148
157
|
next.message.subAgentProgress?.toolsCalled &&
|
|
149
158
|
prev.message.subAgentProgress?.currentTool ===
|
|
150
|
-
next.message.subAgentProgress?.currentTool
|
|
159
|
+
next.message.subAgentProgress?.currentTool &&
|
|
160
|
+
prev.message.subAgentProgress?.tokenUsage?.total ===
|
|
161
|
+
next.message.subAgentProgress?.tokenUsage?.total);
|
|
151
162
|
});
|
|
152
163
|
MessageItem.displayName = 'MessageItem';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AlternateBufferCLI.d.ts","sourceRoot":"","sources":["../../../../../src/cli/ink-cli/components/modes/AlternateBufferCLI.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAG9C,OAAO,KAAK,EAAW,WAAW,EAAE,MAAM,sBAAsB,CAAC;AA2BjE,UAAU,uBAAuB;IAC7B,KAAK,EAAE,UAAU,CAAC;IAClB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,WAAW,EAAE,WAAW,CAAC;IACzB,2EAA2E;IAC3E,kBAAkB,CAAC,EAAE,MAAM,IAAI,CAAC;IAChC,6DAA6D;IAC7D,YAAY,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,wBAAgB,kBAAkB,CAAC,EAC/B,KAAK,EACL,gBAAgB,EAChB,WAAW,EACX,kBAAkB,EAClB,YAAmB,GACtB,EAAE,uBAAuB,
|
|
1
|
+
{"version":3,"file":"AlternateBufferCLI.d.ts","sourceRoot":"","sources":["../../../../../src/cli/ink-cli/components/modes/AlternateBufferCLI.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAG9C,OAAO,KAAK,EAAW,WAAW,EAAE,MAAM,sBAAsB,CAAC;AA2BjE,UAAU,uBAAuB;IAC7B,KAAK,EAAE,UAAU,CAAC;IAClB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,WAAW,EAAE,WAAW,CAAC;IACzB,2EAA2E;IAC3E,kBAAkB,CAAC,EAAE,MAAM,IAAI,CAAC;IAChC,6DAA6D;IAC7D,YAAY,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,wBAAgB,kBAAkB,CAAC,EAC/B,KAAK,EACL,gBAAgB,EAChB,WAAW,EACX,kBAAkB,EAClB,YAAmB,GACtB,EAAE,uBAAuB,2CAkTzB"}
|