dexto 1.5.7 → 1.5.8
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 +2 -0
- package/dist/analytics/events.d.ts +1 -1
- package/dist/analytics/events.d.ts.map +1 -1
- package/dist/cli/auth/constants.d.ts +4 -0
- package/dist/cli/auth/constants.d.ts.map +1 -1
- package/dist/cli/auth/constants.js +4 -0
- package/dist/cli/commands/auth/logout.js +2 -2
- package/dist/cli/commands/billing/status.d.ts +3 -1
- package/dist/cli/commands/billing/status.d.ts.map +1 -1
- package/dist/cli/commands/billing/status.js +23 -1
- package/dist/cli/commands/interactive-commands/prompt-commands.d.ts.map +1 -1
- package/dist/cli/commands/interactive-commands/prompt-commands.js +18 -2
- package/dist/cli/commands/list-agents.d.ts.map +1 -1
- package/dist/cli/commands/list-agents.js +3 -2
- package/dist/cli/commands/setup.d.ts +5 -5
- package/dist/cli/commands/setup.d.ts.map +1 -1
- package/dist/cli/commands/setup.js +766 -207
- package/dist/cli/ink-cli/InkCLIRefactored.d.ts.map +1 -1
- package/dist/cli/ink-cli/InkCLIRefactored.js +11 -1
- package/dist/cli/ink-cli/components/BackgroundTasksPanel.d.ts +18 -0
- package/dist/cli/ink-cli/components/BackgroundTasksPanel.d.ts.map +1 -0
- package/dist/cli/ink-cli/components/BackgroundTasksPanel.js +48 -0
- package/dist/cli/ink-cli/components/ErrorBoundary.js +1 -1
- package/dist/cli/ink-cli/components/Footer.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/Footer.js +4 -4
- package/dist/cli/ink-cli/components/ResourceAutocomplete.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/ResourceAutocomplete.js +150 -41
- package/dist/cli/ink-cli/components/StatusBar.d.ts +3 -1
- package/dist/cli/ink-cli/components/StatusBar.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/StatusBar.js +17 -1
- package/dist/cli/ink-cli/components/chat/MessageItem.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/chat/MessageItem.js +9 -5
- package/dist/cli/ink-cli/components/modes/AlternateBufferCLI.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/modes/AlternateBufferCLI.js +2 -1
- package/dist/cli/ink-cli/components/modes/StaticCLI.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/modes/StaticCLI.js +2 -1
- package/dist/cli/ink-cli/components/overlays/ContextStatsOverlay.js +1 -1
- package/dist/cli/ink-cli/components/overlays/CustomModelWizard.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/overlays/CustomModelWizard.js +8 -4
- package/dist/cli/ink-cli/components/overlays/LogLevelSelector.js +1 -1
- package/dist/cli/ink-cli/components/overlays/McpRemoveSelector.js +1 -1
- package/dist/cli/ink-cli/components/overlays/ModelSelectorRefactored.d.ts +1 -0
- package/dist/cli/ink-cli/components/overlays/ModelSelectorRefactored.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/overlays/ModelSelectorRefactored.js +144 -41
- package/dist/cli/ink-cli/components/overlays/ToolBrowser.d.ts +1 -0
- package/dist/cli/ink-cli/components/overlays/ToolBrowser.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/overlays/ToolBrowser.js +281 -39
- package/dist/cli/ink-cli/components/overlays/custom-model-wizard/provider-config.d.ts +9 -1
- package/dist/cli/ink-cli/components/overlays/custom-model-wizard/provider-config.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/overlays/custom-model-wizard/provider-config.js +35 -9
- package/dist/cli/ink-cli/containers/InputContainer.js +2 -2
- package/dist/cli/ink-cli/containers/OverlayContainer.d.ts.map +1 -1
- package/dist/cli/ink-cli/containers/OverlayContainer.js +134 -23
- package/dist/cli/ink-cli/hooks/useAgentEvents.d.ts.map +1 -1
- package/dist/cli/ink-cli/hooks/useAgentEvents.js +61 -0
- package/dist/cli/ink-cli/hooks/useCLIState.d.ts.map +1 -1
- package/dist/cli/ink-cli/hooks/useCLIState.js +3 -0
- package/dist/cli/ink-cli/hooks/useInputOrchestrator.d.ts.map +1 -1
- package/dist/cli/ink-cli/hooks/useInputOrchestrator.js +8 -0
- package/dist/cli/ink-cli/services/processStream.d.ts.map +1 -1
- package/dist/cli/ink-cli/services/processStream.js +50 -2
- package/dist/cli/ink-cli/state/initialState.d.ts.map +1 -1
- package/dist/cli/ink-cli/state/initialState.js +3 -0
- package/dist/cli/ink-cli/state/types.d.ts +9 -0
- package/dist/cli/ink-cli/state/types.d.ts.map +1 -1
- package/dist/cli/ink-cli/utils/llm-provider-display.d.ts +3 -0
- package/dist/cli/ink-cli/utils/llm-provider-display.d.ts.map +1 -0
- package/dist/cli/ink-cli/utils/llm-provider-display.js +22 -0
- package/dist/cli/ink-cli/utils/messageFormatting.d.ts +4 -6
- package/dist/cli/ink-cli/utils/messageFormatting.d.ts.map +1 -1
- package/dist/cli/ink-cli/utils/messageFormatting.js +77 -9
- package/dist/cli/utils/dexto-auth-check.d.ts +7 -7
- package/dist/cli/utils/dexto-auth-check.d.ts.map +1 -1
- package/dist/cli/utils/dexto-auth-check.js +16 -16
- package/dist/cli/utils/options.js +1 -1
- package/dist/cli/utils/provider-setup.d.ts +2 -2
- package/dist/cli/utils/provider-setup.d.ts.map +1 -1
- package/dist/cli/utils/provider-setup.js +10 -2
- package/dist/config/cli-overrides.js +1 -1
- package/dist/config/effective-llm.d.ts +4 -4
- package/dist/config/effective-llm.d.ts.map +1 -1
- package/dist/config/effective-llm.js +4 -4
- package/dist/index.js +12 -3
- package/dist/webui/assets/{index-Dl3mj53P.js → index-Cz2z7NQ8.js} +74 -74
- package/dist/webui/index.html +1 -1
- package/package.json +7 -7
|
@@ -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;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,MAAM,WAAW,aAAa;IAC1B,kDAAkD;IAClD,UAAU,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,CAAC;IACpF,wEAAwE;IACxE,cAAc,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CACxC;AAED;;GAEG;AACH,wBAAsB,qBAAqB,CACvC,KAAK,EAAE,UAAU,EACjB,gBAAgB,EAAE,MAAM,GAAG,IAAI,EAC/B,OAAO,GAAE,aAAkB,GAC5B,OAAO,CAAC,IAAI,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,MAAM,WAAW,aAAa;IAC1B,kDAAkD;IAClD,UAAU,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,CAAC;IACpF,wEAAwE;IACxE,cAAc,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CACxC;AAED;;GAEG;AACH,wBAAsB,qBAAqB,CACvC,KAAK,EAAE,UAAU,EACjB,gBAAgB,EAAE,MAAM,GAAG,IAAI,EAC/B,OAAO,GAAE,aAAkB,GAC5B,OAAO,CAAC,IAAI,CAAC,CAsFf"}
|
|
@@ -70,7 +70,7 @@ export async function startInkCliRefactored(agent, initialSessionId, options = {
|
|
|
70
70
|
};
|
|
71
71
|
// Initialize sound service from preferences
|
|
72
72
|
const { SoundNotificationService } = await import('./utils/soundNotification.js');
|
|
73
|
-
const { globalPreferencesExist, loadGlobalPreferences } = await import('@dexto/agent-management');
|
|
73
|
+
const { globalPreferencesExist, loadGlobalPreferences, agentPreferencesExist, loadAgentPreferences, } = await import('@dexto/agent-management');
|
|
74
74
|
let soundService = null;
|
|
75
75
|
// Initialize sound config with defaults (enabled by default even without preferences file)
|
|
76
76
|
let soundConfig = {
|
|
@@ -97,6 +97,16 @@ export async function startInkCliRefactored(agent, initialSessionId, options = {
|
|
|
97
97
|
if (soundConfig.enabled) {
|
|
98
98
|
soundService = new SoundNotificationService(soundConfig);
|
|
99
99
|
}
|
|
100
|
+
// Initialize tool preferences (per-agent)
|
|
101
|
+
if (agentPreferencesExist(agent.config.agentId)) {
|
|
102
|
+
try {
|
|
103
|
+
const preferences = await loadAgentPreferences(agent.config.agentId);
|
|
104
|
+
agent.setGlobalDisabledTools(preferences.tools?.disabled ?? []);
|
|
105
|
+
}
|
|
106
|
+
catch (error) {
|
|
107
|
+
agent.logger.debug(`Agent tool preferences could not be loaded: ${error instanceof Error ? error.message : String(error)}`);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
100
110
|
const inkApp = render(_jsx(InkCLIRefactored, { agent: agent, initialSessionId: initialSessionId, startupInfo: startupInfo, soundService: soundService }), {
|
|
101
111
|
exitOnCtrlC: false,
|
|
102
112
|
alternateBuffer: USE_ALTERNATE_BUFFER,
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BackgroundTasksPanel Component
|
|
3
|
+
*
|
|
4
|
+
* Displays background task status in a compact table.
|
|
5
|
+
*/
|
|
6
|
+
interface BackgroundTaskItem {
|
|
7
|
+
taskId: string;
|
|
8
|
+
status: 'running' | 'completed' | 'failed' | 'cancelled';
|
|
9
|
+
description?: string;
|
|
10
|
+
}
|
|
11
|
+
interface BackgroundTasksPanelProps {
|
|
12
|
+
tasks: BackgroundTaskItem[];
|
|
13
|
+
isExpanded: boolean;
|
|
14
|
+
isProcessing?: boolean;
|
|
15
|
+
}
|
|
16
|
+
export declare function BackgroundTasksPanel({ tasks, isExpanded, isProcessing, }: BackgroundTasksPanelProps): import("react/jsx-runtime").JSX.Element | null;
|
|
17
|
+
export {};
|
|
18
|
+
//# sourceMappingURL=BackgroundTasksPanel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BackgroundTasksPanel.d.ts","sourceRoot":"","sources":["../../../../src/cli/ink-cli/components/BackgroundTasksPanel.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,UAAU,kBAAkB;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,SAAS,GAAG,WAAW,GAAG,QAAQ,GAAG,WAAW,CAAC;IACzD,WAAW,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,UAAU,yBAAyB;IAC/B,KAAK,EAAE,kBAAkB,EAAE,CAAC;IAC5B,UAAU,EAAE,OAAO,CAAC;IACpB,YAAY,CAAC,EAAE,OAAO,CAAC;CAC1B;AAsBD,wBAAgB,oBAAoB,CAAC,EACjC,KAAK,EACL,UAAU,EACV,YAAoB,GACvB,EAAE,yBAAyB,kDA+E3B"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Box, Text } from 'ink';
|
|
3
|
+
function padText(value, width) {
|
|
4
|
+
if (value.length >= width)
|
|
5
|
+
return value.slice(0, width - 1) + '…';
|
|
6
|
+
return value.padEnd(width, ' ');
|
|
7
|
+
}
|
|
8
|
+
function formatStatus(status) {
|
|
9
|
+
switch (status) {
|
|
10
|
+
case 'running':
|
|
11
|
+
return 'running';
|
|
12
|
+
case 'completed':
|
|
13
|
+
return 'done';
|
|
14
|
+
case 'failed':
|
|
15
|
+
return 'failed';
|
|
16
|
+
case 'cancelled':
|
|
17
|
+
return 'cancelled';
|
|
18
|
+
default:
|
|
19
|
+
return status;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
export function BackgroundTasksPanel({ tasks, isExpanded, isProcessing = false, }) {
|
|
23
|
+
if (!isExpanded)
|
|
24
|
+
return null;
|
|
25
|
+
const sortedTasks = [...tasks].sort((a, b) => {
|
|
26
|
+
if (a.status === b.status)
|
|
27
|
+
return 0;
|
|
28
|
+
if (a.status === 'running')
|
|
29
|
+
return -1;
|
|
30
|
+
if (b.status === 'running')
|
|
31
|
+
return 1;
|
|
32
|
+
return a.status.localeCompare(b.status);
|
|
33
|
+
});
|
|
34
|
+
const runningCount = tasks.filter((task) => task.status === 'running').length;
|
|
35
|
+
const totalCount = tasks.length;
|
|
36
|
+
const headerText = `🧵 Background Tasks (${runningCount}/${totalCount} running)`;
|
|
37
|
+
if (totalCount === 0) {
|
|
38
|
+
return (_jsxs(Box, { flexDirection: "column", borderStyle: isProcessing ? undefined : 'round', borderColor: "gray", paddingX: 1, marginX: 1, marginBottom: 1, children: [_jsx(Text, { bold: true, color: "cyan", children: headerText }), _jsx(Text, { color: "gray", dimColor: true, children: "No background tasks" })] }));
|
|
39
|
+
}
|
|
40
|
+
const statusWidth = 10;
|
|
41
|
+
const idWidth = 14;
|
|
42
|
+
const descWidth = 48;
|
|
43
|
+
return (_jsxs(Box, { flexDirection: "column", borderStyle: isProcessing ? undefined : 'round', borderColor: "gray", paddingX: 1, marginX: 1, marginBottom: 1, children: [_jsxs(Box, { children: [_jsx(Text, { bold: true, color: "cyan", children: headerText }), _jsxs(Text, { color: "gray", dimColor: true, children: [' ', "\u00B7 ctrl+b to hide tasks"] })] }), _jsx(Box, { children: _jsxs(Text, { color: "gray", children: [padText('status', statusWidth), padText('task id', idWidth), padText('description', descWidth)] }) }), sortedTasks.map((task) => {
|
|
44
|
+
const status = formatStatus(task.status);
|
|
45
|
+
const desc = task.description ?? '';
|
|
46
|
+
return (_jsx(Box, { children: _jsxs(Text, { color: task.status === 'running' ? 'yellow' : 'gray', children: [padText(status, statusWidth), padText(task.taskId, idWidth), padText(desc, descWidth)] }) }, task.taskId));
|
|
47
|
+
})] }));
|
|
48
|
+
}
|
|
@@ -22,7 +22,7 @@ export class ErrorBoundary extends React.Component {
|
|
|
22
22
|
}
|
|
23
23
|
render() {
|
|
24
24
|
if (this.state.hasError) {
|
|
25
|
-
return (_jsxs(Box, { flexDirection: "column", padding: 1, borderStyle: "round", borderColor: "red", children: [_jsx(Text, { color: "red", bold: true, children: "
|
|
25
|
+
return (_jsxs(Box, { flexDirection: "column", padding: 1, borderStyle: "round", borderColor: "red", children: [_jsx(Text, { color: "red", bold: true, children: "CLI Error" }), _jsx(Text, { color: "red", children: this.state.error?.message || 'Unknown error' }), _jsx(Text, { color: "yellowBright", children: "Press Ctrl+C to exit" })] }));
|
|
26
26
|
}
|
|
27
27
|
return this.props.children;
|
|
28
28
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Footer.d.ts","sourceRoot":"","sources":["../../../../src/cli/ink-cli/components/Footer.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,EAAuB,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AAGnE,UAAU,WAAW;IACjB,KAAK,EAAE,UAAU,CAAC;IAClB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,kEAAkE;IAClE,WAAW,CAAC,EAAE,OAAO,CAAC;CACzB;AAOD;;GAEG;AACH,wBAAgB,MAAM,CAAC,EACnB,KAAK,EACL,SAAS,EACT,SAAS,EACT,GAAG,EACH,UAAU,EACV,gBAAgB,EAChB,cAAc,EACd,WAAW,GACd,EAAE,WAAW,
|
|
1
|
+
{"version":3,"file":"Footer.d.ts","sourceRoot":"","sources":["../../../../src/cli/ink-cli/components/Footer.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,EAAuB,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AAGnE,UAAU,WAAW;IACjB,KAAK,EAAE,UAAU,CAAC;IAClB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,kEAAkE;IAClE,WAAW,CAAC,EAAE,OAAO,CAAC;CACzB;AAOD;;GAEG;AACH,wBAAgB,MAAM,CAAC,EACnB,KAAK,EACL,SAAS,EACT,SAAS,EACT,GAAG,EACH,UAAU,EACV,gBAAgB,EAChB,cAAc,EACd,WAAW,GACd,EAAE,WAAW,2CAiHb"}
|
|
@@ -7,7 +7,7 @@ import { useEffect, useState } from 'react';
|
|
|
7
7
|
import path from 'node:path';
|
|
8
8
|
import { Box, Text } from 'ink';
|
|
9
9
|
import { getModelDisplayName } from '@dexto/core';
|
|
10
|
-
import {
|
|
10
|
+
import { getLLMProviderDisplayName } from '../utils/llm-provider-display.js';
|
|
11
11
|
function getDirectoryName(cwd) {
|
|
12
12
|
const base = path.basename(cwd);
|
|
13
13
|
return base || cwd;
|
|
@@ -20,8 +20,8 @@ export function Footer({ agent, sessionId, modelName, cwd, branchName, autoAppro
|
|
|
20
20
|
const displayModelName = getModelDisplayName(modelName);
|
|
21
21
|
const [contextLeft, setContextLeft] = useState(null);
|
|
22
22
|
// Provider is session-scoped because /model can switch LLM per session.
|
|
23
|
-
const
|
|
24
|
-
|
|
23
|
+
const provider = sessionId ? agent.getCurrentLLMConfig(sessionId).provider : null;
|
|
24
|
+
const providerLabel = provider ? getLLMProviderDisplayName(provider) : null;
|
|
25
25
|
useEffect(() => {
|
|
26
26
|
if (!sessionId) {
|
|
27
27
|
setContextLeft(null);
|
|
@@ -73,5 +73,5 @@ export function Footer({ agent, sessionId, modelName, cwd, branchName, autoAppro
|
|
|
73
73
|
}, [agent, sessionId]);
|
|
74
74
|
// Shell mode changes the path color to yellow as indicator
|
|
75
75
|
const pathColor = isShellMode ? 'yellow' : 'blue';
|
|
76
|
-
return (_jsxs(Box, { flexDirection: "column", paddingX: 1, children: [_jsxs(Box, { flexDirection: "row", justifyContent: "space-between", children: [_jsxs(Box, { children: [_jsx(Text, { color: pathColor, children: displayPath }), branchName && _jsxs(Text, { color: "gray", children: [" (", branchName, ")"] })] }), _jsxs(Box, { children: [_jsx(Text, { color: "cyan", children: displayModelName }),
|
|
76
|
+
return (_jsxs(Box, { flexDirection: "column", paddingX: 1, children: [_jsxs(Box, { flexDirection: "row", justifyContent: "space-between", children: [_jsxs(Box, { children: [_jsx(Text, { color: pathColor, children: displayPath }), branchName && _jsxs(Text, { color: "gray", children: [" (", branchName, ")"] })] }), _jsxs(Box, { children: [_jsx(Text, { color: "cyan", children: displayModelName }), providerLabel && _jsxs(Text, { color: "gray", children: [" (", providerLabel, ")"] })] })] }), contextLeft && (_jsx(Box, { children: _jsxs(Text, { color: "gray", children: [contextLeft.percentLeft, "% context left"] }) })), isShellMode && (_jsxs(Box, { children: [_jsx(Text, { color: "yellow", bold: true, children: "!" }), _jsx(Text, { color: "gray", children: " for shell mode" })] })), planModeActive && !isShellMode && (_jsxs(Box, { children: [_jsx(Text, { color: "magentaBright", children: "plan mode" }), _jsx(Text, { color: "gray", children: " (shift + tab to cycle)" })] })), autoApproveEdits && !planModeActive && !isShellMode && (_jsxs(Box, { children: [_jsx(Text, { color: "yellowBright", children: "accept edits" }), _jsx(Text, { color: "gray", children: " (shift + tab to cycle)" })] }))] }));
|
|
77
77
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ResourceAutocomplete.d.ts","sourceRoot":"","sources":["../../../../src/cli/ink-cli/components/ResourceAutocomplete.tsx"],"names":[],"mappings":"AAAA,OAAO,KAQN,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"ResourceAutocomplete.d.ts","sourceRoot":"","sources":["../../../../src/cli/ink-cli/components/ResourceAutocomplete.tsx"],"names":[],"mappings":"AAAA,OAAO,KAQN,MAAM,OAAO,CAAC;AAGf,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,kCAAkC,CAAC;AAC5D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAG9C,MAAM,WAAW,0BAA0B;IACvC,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,KAAK,OAAO,CAAC;CACrD;AAED,UAAU,yBAAyB;IAC/B,SAAS,EAAE,OAAO,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,gBAAgB,EAAE,CAAC,QAAQ,EAAE,gBAAgB,KAAK,IAAI,CAAC;IACvD,eAAe,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,KAAK,EAAE,UAAU,CAAC;CACrB;AAsFD;;GAEG;AACH,QAAA,MAAM,yBAAyB,8GA6W9B,CAAC;AAEF;;;GAGG;AACH,QAAA,MAAM,oBAAoB,EAErB,OAAO,yBAAyB,CAAC;AAEtC,eAAe,oBAAoB,CAAC"}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import React, { useState, useEffect, useRef, useMemo, useCallback, forwardRef, useImperativeHandle, } from 'react';
|
|
3
3
|
import { Box, Text } from 'ink';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import { centerTruncatePath } from '../utils/messageFormatting.js';
|
|
4
6
|
/**
|
|
5
7
|
* Get match score for resource: 0 = no match, 1 = description/URI match, 2 = name includes, 3 = name starts with
|
|
6
8
|
* Prioritizes name matches over description/URI matches
|
|
@@ -11,7 +13,7 @@ function getResourceMatchScore(resource, query) {
|
|
|
11
13
|
const lowerQuery = query.toLowerCase();
|
|
12
14
|
const name = (resource.name || '').toLowerCase();
|
|
13
15
|
const uri = resource.uri.toLowerCase();
|
|
14
|
-
const uriFilename = uri.split(
|
|
16
|
+
const uriFilename = uri.split(/[\\/]/).pop()?.toLowerCase() || '';
|
|
15
17
|
const description = (resource.description || '').toLowerCase();
|
|
16
18
|
// Highest priority: name starts with query
|
|
17
19
|
if (name.startsWith(lowerQuery)) {
|
|
@@ -139,27 +141,127 @@ const ResourceAutocompleteInner = forwardRef(function ResourceAutocomplete({ isV
|
|
|
139
141
|
}
|
|
140
142
|
return '';
|
|
141
143
|
}, [searchQuery]);
|
|
142
|
-
//
|
|
143
|
-
const
|
|
144
|
-
const
|
|
145
|
-
|
|
144
|
+
// Extract directories and create display items (hybrid search)
|
|
145
|
+
const displayItems = useMemo(() => {
|
|
146
|
+
const items = [];
|
|
147
|
+
const directories = new Set();
|
|
148
|
+
// Process each resource to extract paths and directories
|
|
149
|
+
resources.forEach((resource) => {
|
|
150
|
+
// Convert URI to relative path
|
|
151
|
+
let relativePath = resource.uri;
|
|
152
|
+
const rawUri = relativePath.replace(/^(fs|file):\/\//, '');
|
|
153
|
+
if (path.isAbsolute(rawUri)) {
|
|
154
|
+
try {
|
|
155
|
+
const relPath = path.relative(process.cwd(), rawUri);
|
|
156
|
+
if (relPath && !relPath.startsWith('..')) {
|
|
157
|
+
relativePath = relPath;
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
// Outside cwd, use name as fallback
|
|
161
|
+
const uriParts = resource.uri.split(/[\\/]/);
|
|
162
|
+
relativePath =
|
|
163
|
+
resource.name || uriParts[uriParts.length - 1] || resource.uri;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
catch {
|
|
167
|
+
return; // Skip if path conversion fails
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
// Add file item
|
|
171
|
+
items.push({
|
|
172
|
+
path: relativePath,
|
|
173
|
+
isDirectory: false,
|
|
174
|
+
resource,
|
|
175
|
+
});
|
|
176
|
+
// Extract all parent directories (1-2 levels deep)
|
|
177
|
+
const segments = relativePath.split(path.sep).filter(Boolean);
|
|
178
|
+
for (let i = 0; i < Math.min(segments.length - 1, 2); i++) {
|
|
179
|
+
const dirPath = segments.slice(0, i + 1).join(path.sep) + path.sep;
|
|
180
|
+
directories.add(dirPath);
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
// Add directory items
|
|
184
|
+
directories.forEach((dirPath) => {
|
|
185
|
+
items.push({
|
|
186
|
+
path: dirPath,
|
|
187
|
+
isDirectory: true,
|
|
188
|
+
});
|
|
189
|
+
});
|
|
190
|
+
// Filter by query
|
|
191
|
+
const filtered = items.filter((item) => {
|
|
192
|
+
if (!mentionQuery)
|
|
193
|
+
return true; // Show all when no query
|
|
194
|
+
const lowerQuery = mentionQuery.toLowerCase();
|
|
195
|
+
const lowerPath = item.path.toLowerCase();
|
|
196
|
+
const pathParts = item.path.split(path.sep).filter(Boolean);
|
|
197
|
+
const lastSegment = pathParts[pathParts.length - 1]?.toLowerCase() || '';
|
|
198
|
+
// Match against filename/dirname or full path
|
|
199
|
+
if (lastSegment.includes(lowerQuery) || lowerPath.includes(lowerQuery)) {
|
|
200
|
+
return true;
|
|
201
|
+
}
|
|
202
|
+
// Also match against resource name and description (for files)
|
|
203
|
+
if (item.resource) {
|
|
204
|
+
const lowerName = (item.resource.name || '').toLowerCase();
|
|
205
|
+
const lowerDescription = (item.resource.description || '').toLowerCase();
|
|
206
|
+
if (lowerName.includes(lowerQuery) || lowerDescription.includes(lowerQuery)) {
|
|
207
|
+
return true;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
return false;
|
|
211
|
+
});
|
|
212
|
+
// Sort by relevance
|
|
213
|
+
return filtered.sort((a, b) => {
|
|
214
|
+
if (!mentionQuery) {
|
|
215
|
+
// No query: directories first, then alphabetically
|
|
216
|
+
if (a.isDirectory !== b.isDirectory) {
|
|
217
|
+
return a.isDirectory ? -1 : 1;
|
|
218
|
+
}
|
|
219
|
+
return a.path.localeCompare(b.path);
|
|
220
|
+
}
|
|
221
|
+
const lowerQuery = mentionQuery.toLowerCase();
|
|
222
|
+
const aPathParts = a.path.split(path.sep).filter(Boolean);
|
|
223
|
+
const bPathParts = b.path.split(path.sep).filter(Boolean);
|
|
224
|
+
const aLastSegment = aPathParts[aPathParts.length - 1]?.toLowerCase() || '';
|
|
225
|
+
const bLastSegment = bPathParts[bPathParts.length - 1]?.toLowerCase() || '';
|
|
226
|
+
// Score by match quality
|
|
227
|
+
const aStartsWith = aLastSegment.startsWith(lowerQuery);
|
|
228
|
+
const bStartsWith = bLastSegment.startsWith(lowerQuery);
|
|
229
|
+
const aIncludes = aLastSegment.includes(lowerQuery);
|
|
230
|
+
const bIncludes = bLastSegment.includes(lowerQuery);
|
|
231
|
+
// Priority 1: Prefix matches
|
|
232
|
+
if (aStartsWith && !bStartsWith)
|
|
233
|
+
return -1;
|
|
234
|
+
if (!aStartsWith && bStartsWith)
|
|
235
|
+
return 1;
|
|
236
|
+
// Priority 2: Substring matches
|
|
237
|
+
if (aIncludes && !bIncludes)
|
|
238
|
+
return -1;
|
|
239
|
+
if (!aIncludes && bIncludes)
|
|
240
|
+
return 1;
|
|
241
|
+
// Priority 3: Shallower paths first
|
|
242
|
+
const depthDiff = aPathParts.length - bPathParts.length;
|
|
243
|
+
if (depthDiff !== 0)
|
|
244
|
+
return depthDiff;
|
|
245
|
+
// Priority 4: Alphabetically
|
|
246
|
+
return a.path.localeCompare(b.path);
|
|
247
|
+
});
|
|
146
248
|
}, [resources, mentionQuery]);
|
|
147
249
|
// Track items length for reset detection
|
|
148
|
-
const prevItemsLengthRef = useRef(
|
|
149
|
-
const itemsChanged =
|
|
250
|
+
const prevItemsLengthRef = useRef(displayItems.length);
|
|
251
|
+
const itemsChanged = displayItems.length !== prevItemsLengthRef.current;
|
|
150
252
|
// Derive clamped selection values during render (always valid, no setState needed)
|
|
151
253
|
// This prevents the double-render that was causing flickering
|
|
152
254
|
const selectedIndex = itemsChanged
|
|
153
255
|
? 0
|
|
154
|
-
: Math.min(selection.index, Math.max(0,
|
|
256
|
+
: Math.min(selection.index, Math.max(0, displayItems.length - 1));
|
|
155
257
|
const scrollOffset = itemsChanged
|
|
156
258
|
? 0
|
|
157
|
-
: Math.min(selection.offset, Math.max(0,
|
|
259
|
+
: Math.min(selection.offset, Math.max(0, displayItems.length - MAX_VISIBLE_ITEMS));
|
|
158
260
|
// Sync state only when items actually changed AND state differs
|
|
159
261
|
// This effect runs AFTER render, updating state for next user interaction
|
|
160
262
|
useEffect(() => {
|
|
161
263
|
if (itemsChanged) {
|
|
162
|
-
prevItemsLengthRef.current =
|
|
264
|
+
prevItemsLengthRef.current = displayItems.length;
|
|
163
265
|
// Only setState if values actually differ (prevents unnecessary re-render)
|
|
164
266
|
if (selection.index !== 0 || selection.offset !== 0) {
|
|
165
267
|
selectedIndexRef.current = 0;
|
|
@@ -169,11 +271,11 @@ const ResourceAutocompleteInner = forwardRef(function ResourceAutocomplete({ isV
|
|
|
169
271
|
selectedIndexRef.current = 0;
|
|
170
272
|
}
|
|
171
273
|
}
|
|
172
|
-
}, [itemsChanged,
|
|
274
|
+
}, [itemsChanged, displayItems.length, selection.index, selection.offset]);
|
|
173
275
|
// Calculate visible items based on scroll offset
|
|
174
276
|
const visibleResources = useMemo(() => {
|
|
175
|
-
return
|
|
176
|
-
}, [
|
|
277
|
+
return displayItems.slice(scrollOffset, scrollOffset + MAX_VISIBLE_ITEMS);
|
|
278
|
+
}, [displayItems, scrollOffset, MAX_VISIBLE_ITEMS]);
|
|
177
279
|
// Expose handleInput method via ref
|
|
178
280
|
useImperativeHandle(ref, () => ({
|
|
179
281
|
handleInput: (_input, key) => {
|
|
@@ -184,7 +286,7 @@ const ResourceAutocompleteInner = forwardRef(function ResourceAutocomplete({ isV
|
|
|
184
286
|
onClose();
|
|
185
287
|
return true;
|
|
186
288
|
}
|
|
187
|
-
const itemsLength =
|
|
289
|
+
const itemsLength = displayItems.length;
|
|
188
290
|
if (itemsLength === 0)
|
|
189
291
|
return false;
|
|
190
292
|
if (key.upArrow) {
|
|
@@ -195,41 +297,50 @@ const ResourceAutocompleteInner = forwardRef(function ResourceAutocomplete({ isV
|
|
|
195
297
|
updateSelection((prev) => (prev + 1) % itemsLength);
|
|
196
298
|
return true;
|
|
197
299
|
}
|
|
198
|
-
// Tab to load into input (for editing
|
|
300
|
+
// Tab to load into input (for editing/browsing)
|
|
199
301
|
if (key.tab) {
|
|
200
|
-
const
|
|
201
|
-
if (!
|
|
302
|
+
const item = displayItems[selectedIndexRef.current];
|
|
303
|
+
if (!item)
|
|
202
304
|
return false;
|
|
203
|
-
// Get the @ position and construct the text to load
|
|
204
305
|
const atIndex = searchQuery.lastIndexOf('@');
|
|
306
|
+
const reference = item.path; // Already a relative path
|
|
205
307
|
if (atIndex >= 0) {
|
|
206
308
|
const before = searchQuery.slice(0, atIndex + 1);
|
|
207
|
-
const uriParts = resource.uri.split('/');
|
|
208
|
-
const reference = resource.name || uriParts[uriParts.length - 1] || resource.uri;
|
|
209
309
|
onLoadIntoInput?.(`${before}${reference}`);
|
|
210
310
|
}
|
|
211
311
|
else {
|
|
212
|
-
// Fallback: just append @resource
|
|
213
|
-
const uriParts = resource.uri.split('/');
|
|
214
|
-
const reference = resource.name || uriParts[uriParts.length - 1] || resource.uri;
|
|
215
312
|
onLoadIntoInput?.(`${searchQuery}@${reference}`);
|
|
216
313
|
}
|
|
217
314
|
return true;
|
|
218
315
|
}
|
|
219
|
-
// Enter to select
|
|
316
|
+
// Enter to select (directories drill down, files select)
|
|
220
317
|
if (key.return) {
|
|
221
|
-
const
|
|
222
|
-
if (
|
|
223
|
-
|
|
224
|
-
|
|
318
|
+
const item = displayItems[selectedIndexRef.current];
|
|
319
|
+
if (!item)
|
|
320
|
+
return false;
|
|
321
|
+
if (item.isDirectory) {
|
|
322
|
+
// Drill down into directory
|
|
323
|
+
const atIndex = searchQuery.lastIndexOf('@');
|
|
324
|
+
if (atIndex >= 0) {
|
|
325
|
+
const before = searchQuery.slice(0, atIndex + 1);
|
|
326
|
+
onLoadIntoInput?.(`${before}${item.path}`);
|
|
327
|
+
}
|
|
328
|
+
else {
|
|
329
|
+
onLoadIntoInput?.(`${searchQuery}@${item.path}`);
|
|
330
|
+
}
|
|
225
331
|
}
|
|
332
|
+
else if (item.resource) {
|
|
333
|
+
// Select the file resource
|
|
334
|
+
onSelectResource(item.resource);
|
|
335
|
+
}
|
|
336
|
+
return true;
|
|
226
337
|
}
|
|
227
338
|
// Don't consume other keys (typing, backspace, etc.)
|
|
228
339
|
return false;
|
|
229
340
|
},
|
|
230
341
|
}), [
|
|
231
342
|
isVisible,
|
|
232
|
-
|
|
343
|
+
displayItems,
|
|
233
344
|
selectedIndexRef,
|
|
234
345
|
searchQuery,
|
|
235
346
|
onClose,
|
|
@@ -242,22 +353,20 @@ const ResourceAutocompleteInner = forwardRef(function ResourceAutocomplete({ isV
|
|
|
242
353
|
if (isLoading) {
|
|
243
354
|
return (_jsx(Box, { paddingX: 0, paddingY: 0, children: _jsx(Text, { color: "gray", children: "Loading resources..." }) }));
|
|
244
355
|
}
|
|
245
|
-
if (
|
|
356
|
+
if (displayItems.length === 0) {
|
|
246
357
|
return (_jsx(Box, { paddingX: 0, paddingY: 0, children: _jsx(Text, { color: "gray", children: mentionQuery
|
|
247
358
|
? `No resources match "${mentionQuery}"`
|
|
248
359
|
: 'No resources available. Connect an MCP server or enable internal resources.' }) }));
|
|
249
360
|
}
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
return (_jsxs(Box, { children: [isImage && _jsx(Text, { color: isSelected ? 'cyan' : 'gray', children: "\uD83D\uDDBC\uFE0F " }), _jsx(Text, { color: isSelected ? 'cyan' : 'white', bold: isSelected, children: displayName }), resource.serverName && (_jsxs(Text, { color: "gray", children: [" [", resource.serverName, "]"] })), _jsxs(Text, { color: "gray", children: [" ", truncatedUri] })] }, resource.uri));
|
|
260
|
-
})] }));
|
|
361
|
+
return (_jsx(Box, { flexDirection: "column", paddingLeft: 2, children: visibleResources.map((item, visibleIndex) => {
|
|
362
|
+
const actualIndex = scrollOffset + visibleIndex;
|
|
363
|
+
const isSelected = actualIndex === selectedIndex;
|
|
364
|
+
// Use center truncation for long paths
|
|
365
|
+
const displayPath = centerTruncatePath(item.path, 60);
|
|
366
|
+
// Check if it's an image file
|
|
367
|
+
const isImage = item.resource?.mimeType?.startsWith('image/');
|
|
368
|
+
return (_jsxs(Box, { children: [_jsx(Text, { color: isSelected ? 'cyan' : 'gray', children: isSelected ? '❯ ' : ' ' }), _jsxs(Text, { color: isSelected ? 'cyan' : 'white', bold: isSelected, children: [isImage && '🖼️ ', displayPath, item.resource?.serverName && ` [${item.resource.serverName}]`] })] }, item.path));
|
|
369
|
+
}) }));
|
|
261
370
|
});
|
|
262
371
|
/**
|
|
263
372
|
* Export with React.memo to prevent unnecessary re-renders from parent
|
|
@@ -25,6 +25,8 @@ interface StatusBarProps {
|
|
|
25
25
|
planModeActive?: boolean;
|
|
26
26
|
/** Whether accept all edits mode is active */
|
|
27
27
|
autoApproveEdits?: boolean;
|
|
28
|
+
/** Number of running background tasks */
|
|
29
|
+
backgroundTasksRunning?: number;
|
|
28
30
|
}
|
|
29
31
|
/**
|
|
30
32
|
* Status bar that shows processing state above input area
|
|
@@ -34,6 +36,6 @@ interface StatusBarProps {
|
|
|
34
36
|
* - Hide spinner during approval wait (user is reviewing, not waiting)
|
|
35
37
|
* - Only show elapsed time after 30s (avoid visual noise for fast operations)
|
|
36
38
|
*/
|
|
37
|
-
export declare function StatusBar({ agent, isProcessing, isThinking, isCompacting, approvalQueueCount, copyModeEnabled, isAwaitingApproval, todoExpanded, hasTodos, planModeActive, autoApproveEdits, }: StatusBarProps): import("react/jsx-runtime").JSX.Element | null;
|
|
39
|
+
export declare function StatusBar({ agent, isProcessing, isThinking, isCompacting, approvalQueueCount, copyModeEnabled, isAwaitingApproval, todoExpanded, hasTodos, planModeActive, autoApproveEdits, backgroundTasksRunning, }: StatusBarProps): import("react/jsx-runtime").JSX.Element | null;
|
|
38
40
|
export {};
|
|
39
41
|
//# 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,YAAY,EAAE,OAAO,CAAC;IACtB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,oDAAoD;IACpD,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,wCAAwC;IACxC,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,yCAAyC;IACzC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,kCAAkC;IAClC,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,8CAA8C;IAC9C,gBAAgB,CAAC,EAAE,OAAO,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;IAC7B,wCAAwC;IACxC,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,yCAAyC;IACzC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,kCAAkC;IAClC,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,8CAA8C;IAC9C,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,yCAAyC;IACzC,sBAAsB,CAAC,EAAE,MAAM,CAAC;CACnC;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,EACtB,KAAK,EACL,YAAY,EACZ,UAAU,EACV,YAAY,EACZ,kBAAkB,EAClB,eAAuB,EACvB,kBAA0B,EAC1B,YAAmB,EACnB,QAAgB,EAChB,cAAsB,EACtB,gBAAwB,EACxB,sBAA0B,GAC7B,EAAE,cAAc,kDAyIhB"}
|
|
@@ -21,7 +21,7 @@ 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, isCompacting, approvalQueueCount, copyModeEnabled = false, isAwaitingApproval = false, todoExpanded = true, hasTodos = false, planModeActive = false, autoApproveEdits = false, }) {
|
|
24
|
+
export function StatusBar({ agent, isProcessing, isThinking, isCompacting, approvalQueueCount, copyModeEnabled = false, isAwaitingApproval = false, todoExpanded = true, hasTodos = false, planModeActive = false, autoApproveEdits = false, backgroundTasksRunning = 0, }) {
|
|
25
25
|
// Cycle through witty phrases while processing (not during compacting)
|
|
26
26
|
const { phrase } = usePhraseCycler({ isActive: isProcessing && !isCompacting });
|
|
27
27
|
// Track elapsed time during processing
|
|
@@ -48,11 +48,17 @@ export function StatusBar({ agent, isProcessing, isThinking, isCompacting, appro
|
|
|
48
48
|
? 'ctrl+t to hide tasks'
|
|
49
49
|
: 'ctrl+t to show tasks'
|
|
50
50
|
: null;
|
|
51
|
+
const backgroundHint = backgroundTasksRunning > 0 ? 'ctrl+b to view bg tasks' : null;
|
|
51
52
|
// Show compacting state - yellow/orange color to indicate context management
|
|
52
53
|
if (isCompacting) {
|
|
53
54
|
const metaParts = [];
|
|
54
55
|
if (showTime)
|
|
55
56
|
metaParts.push(`(${elapsedTime})`);
|
|
57
|
+
if (backgroundTasksRunning > 0) {
|
|
58
|
+
metaParts.push(`${backgroundTasksRunning} bg task${backgroundTasksRunning > 1 ? 's' : ''}`);
|
|
59
|
+
}
|
|
60
|
+
if (backgroundHint)
|
|
61
|
+
metaParts.push(backgroundHint);
|
|
56
62
|
metaParts.push('Esc to cancel');
|
|
57
63
|
if (todoHint)
|
|
58
64
|
metaParts.push(todoHint);
|
|
@@ -68,6 +74,11 @@ export function StatusBar({ agent, isProcessing, isThinking, isCompacting, appro
|
|
|
68
74
|
metaParts.push(`(${elapsedTime})`);
|
|
69
75
|
if (tokenCount)
|
|
70
76
|
metaParts.push(tokenCount);
|
|
77
|
+
if (backgroundTasksRunning > 0) {
|
|
78
|
+
metaParts.push(`${backgroundTasksRunning} bg task${backgroundTasksRunning > 1 ? 's' : ''}`);
|
|
79
|
+
}
|
|
80
|
+
if (backgroundHint)
|
|
81
|
+
metaParts.push(backgroundHint);
|
|
71
82
|
metaParts.push('Esc to cancel');
|
|
72
83
|
if (todoHint)
|
|
73
84
|
metaParts.push(todoHint);
|
|
@@ -82,6 +93,11 @@ export function StatusBar({ agent, isProcessing, isThinking, isCompacting, appro
|
|
|
82
93
|
metaParts.push(`(${elapsedTime})`);
|
|
83
94
|
if (tokenCount)
|
|
84
95
|
metaParts.push(tokenCount);
|
|
96
|
+
if (backgroundTasksRunning > 0) {
|
|
97
|
+
metaParts.push(`${backgroundTasksRunning} bg task${backgroundTasksRunning > 1 ? 's' : ''}`);
|
|
98
|
+
}
|
|
99
|
+
if (backgroundHint)
|
|
100
|
+
metaParts.push(backgroundHint);
|
|
85
101
|
metaParts.push('Esc to cancel');
|
|
86
102
|
if (todoHint)
|
|
87
103
|
metaParts.push(todoHint);
|
|
@@ -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;
|
|
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;AAoD9B,UAAU,gBAAgB;IACtB,OAAO,EAAE,OAAO,CAAC;IACjB,2DAA2D;IAC3D,aAAa,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;;;;;GAMG;AACH,eAAO,MAAM,WAAW,mEACc,gBAAgB,6CAyOrD,CAAC"}
|
|
@@ -11,6 +11,7 @@ import { ConfigBox, StatsBox, HelpBox, SessionListBox, SessionHistoryBox, LogCon
|
|
|
11
11
|
import { ToolResultRenderer } from '../renderers/index.js';
|
|
12
12
|
import { MarkdownText } from '../shared/MarkdownText.js';
|
|
13
13
|
import { ToolIcon } from './ToolIcon.js';
|
|
14
|
+
import { formatToolResultPreview } from '../../utils/messageFormatting.js';
|
|
14
15
|
/**
|
|
15
16
|
* Strip <plan-mode>...</plan-mode> tags from content.
|
|
16
17
|
* Plan mode instructions are injected for the LLM but should not be shown in the UI.
|
|
@@ -120,10 +121,13 @@ export const MessageItem = memo(({ message, terminalWidth = 80 }) => {
|
|
|
120
121
|
const isPending = message.toolStatus === 'pending' || message.toolStatus === 'pending_approval';
|
|
121
122
|
// Check for sub-agent progress data
|
|
122
123
|
const subAgentProgress = message.subAgentProgress;
|
|
124
|
+
const contentLines = message.content.split('\n');
|
|
125
|
+
const headerLine = contentLines[0] ?? '';
|
|
126
|
+
const subHeaderLine = contentLines.length > 1 ? contentLines[1] : '';
|
|
123
127
|
// Parse tool name and args for bold formatting: "ToolName(args)" → bold name + normal args
|
|
124
|
-
const parenIndex =
|
|
125
|
-
const toolName = parenIndex > 0 ?
|
|
126
|
-
const toolArgs = parenIndex > 0 ?
|
|
128
|
+
const parenIndex = headerLine.indexOf('(');
|
|
129
|
+
const toolName = parenIndex > 0 ? headerLine.slice(0, parenIndex) : headerLine;
|
|
130
|
+
const toolArgs = parenIndex > 0 ? headerLine.slice(parenIndex) : '';
|
|
127
131
|
// Build the full tool header text for wrapping
|
|
128
132
|
// Don't include status suffix if we have sub-agent progress (it shows its own status)
|
|
129
133
|
const statusSuffix = subAgentProgress
|
|
@@ -143,10 +147,10 @@ export const MessageItem = memo(({ message, terminalWidth = 80 }) => {
|
|
|
143
147
|
trim: false,
|
|
144
148
|
});
|
|
145
149
|
const toolLines = wrappedToolText.split('\n');
|
|
146
|
-
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 &&
|
|
150
|
+
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))), subHeaderLine && (_jsx(Box, { marginLeft: 2, children: _jsx(Text, { color: "gray", children: subHeaderLine }) })), 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 &&
|
|
147
151
|
subAgentProgress.tokenUsage.total > 0
|
|
148
152
|
? ` | ${subAgentProgress.tokenUsage.total.toLocaleString()} tokens`
|
|
149
|
-
: ''] }) })), hasStructuredDisplay ? (_jsx(ToolResultRenderer, { display: message.toolDisplayData, content: message.toolContent })) : (message.toolResult && (_jsx(Box, { flexDirection: "column", children: _jsxs(Text, { color: "gray", children: ["
|
|
153
|
+
: ''] }) })), hasStructuredDisplay ? (_jsx(ToolResultRenderer, { display: message.toolDisplayData, content: message.toolContent })) : (message.toolResult && (_jsx(Box, { flexDirection: "column", children: _jsxs(Text, { color: "gray", children: ["\u23BF ", formatToolResultPreview(message.toolResult)] }) })))] }));
|
|
150
154
|
}
|
|
151
155
|
// System message: Compact gray text
|
|
152
156
|
return (_jsx(Box, { flexDirection: "column", marginBottom: 1, width: terminalWidth, children: _jsx(Text, { color: "gray", children: message.content }) }));
|
|
@@ -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;
|
|
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;AA8BjE,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,2CAyVzB"}
|
|
@@ -25,6 +25,7 @@ import { StatusBar } from '../StatusBar.js';
|
|
|
25
25
|
import { HistorySearchBar } from '../HistorySearchBar.js';
|
|
26
26
|
import { Footer } from '../Footer.js';
|
|
27
27
|
import { TodoPanel } from '../TodoPanel.js';
|
|
28
|
+
import { BackgroundTasksPanel } from '../BackgroundTasksPanel.js';
|
|
28
29
|
import { VirtualizedList, SCROLL_TO_ITEM_END, } from '../shared/VirtualizedList.js';
|
|
29
30
|
// Containers
|
|
30
31
|
import { InputContainer } from '../../containers/InputContainer.js';
|
|
@@ -175,5 +176,5 @@ export function AlternateBufferCLI({ agent, initialSessionId, startupInfo, onSel
|
|
|
175
176
|
return 'header';
|
|
176
177
|
return item.message.id;
|
|
177
178
|
}, []);
|
|
178
|
-
return (_jsxs(Box, { flexDirection: "column", height: terminalHeight, children: [_jsx(Box, { ref: listContainerRef, flexGrow: 1, flexShrink: 1, minHeight: 0, children: _jsx(VirtualizedList, { ref: listRef, data: listData, renderItem: renderListItem, estimatedItemHeight: estimateItemHeight, keyExtractor: getItemKey, initialScrollIndex: SCROLL_TO_ITEM_END, initialScrollOffsetInIndex: SCROLL_TO_ITEM_END }) }), _jsxs(Box, { flexDirection: "column", flexShrink: 0, children: [_jsx(StatusBar, { agent: agent, isProcessing: ui.isProcessing, isThinking: ui.isThinking, isCompacting: ui.isCompacting, approvalQueueCount: approvalQueue.length, copyModeEnabled: ui.copyModeEnabled, isAwaitingApproval: approval !== null, todoExpanded: ui.todoExpanded, hasTodos: todos.some((t) => t.status !== 'completed'), planModeActive: ui.planModeActive, autoApproveEdits: ui.autoApproveEdits }), _jsx(TodoPanel, { todos: todos, isExpanded: ui.todoExpanded, isProcessing: ui.isProcessing }), selectionHintVisible && (_jsx(Box, { paddingX: 1, children: _jsx(Text, { color: "yellowBright", children: "\uD83D\uDCA1 Tip: Hold Option (\u2325) and click to select text, or press Ctrl+S to toggle copy mode" }) })), _jsx(QueuedMessagesDisplay, { messages: queuedMessages }), _jsx(InputContainer, { ref: inputContainerRef, buffer: buffer, input: input, ui: ui, session: session, approval: approval, queuedMessages: queuedMessages, setInput: setInput, setUi: setUi, setSession: setSession, setMessages: setMessages, setPendingMessages: setPendingMessages, setDequeuedBuffer: setDequeuedBuffer, setQueuedMessages: setQueuedMessages, setApproval: setApproval, setApprovalQueue: setApprovalQueue, setTodos: setTodos, agent: agent, inputService: inputService, onKeyboardScroll: handleKeyboardScroll, useStreaming: useStreaming }), _jsx(OverlayContainer, { ref: overlayContainerRef, ui: ui, input: input, session: session, approval: approval, setInput: setInput, setUi: setUi, setSession: setSession, setMessages: setMessages, setApproval: setApproval, setApprovalQueue: setApprovalQueue, agent: agent, inputService: inputService, buffer: buffer, onSubmitPromptCommand: handleSubmitPromptCommand }), ui.exitWarningShown && (_jsxs(Box, { paddingX: 1, children: [_jsx(Text, { color: "yellowBright", bold: true, children: "\u26A0 Press Ctrl+C again to exit" }), _jsx(Text, { color: "gray", children: " (or press any key to cancel)" })] })), _jsx(Footer, { agent: agent, sessionId: session.id, modelName: session.modelName, cwd: process.cwd(), ...(branchName ? { branchName } : {}), autoApproveEdits: ui.autoApproveEdits, planModeActive: ui.planModeActive, isShellMode: buffer.text.startsWith('!') }), ui.historySearch.isActive && (_jsx(HistorySearchBar, { query: ui.historySearch.query, hasMatch: historySearchHasMatch }))] })] }));
|
|
179
|
+
return (_jsxs(Box, { flexDirection: "column", height: terminalHeight, children: [_jsx(Box, { ref: listContainerRef, flexGrow: 1, flexShrink: 1, minHeight: 0, children: _jsx(VirtualizedList, { ref: listRef, data: listData, renderItem: renderListItem, estimatedItemHeight: estimateItemHeight, keyExtractor: getItemKey, initialScrollIndex: SCROLL_TO_ITEM_END, initialScrollOffsetInIndex: SCROLL_TO_ITEM_END }) }), _jsxs(Box, { flexDirection: "column", flexShrink: 0, children: [_jsx(StatusBar, { agent: agent, isProcessing: ui.isProcessing, isThinking: ui.isThinking, isCompacting: ui.isCompacting, approvalQueueCount: approvalQueue.length, copyModeEnabled: ui.copyModeEnabled, isAwaitingApproval: approval !== null, todoExpanded: ui.todoExpanded, hasTodos: todos.some((t) => t.status !== 'completed'), planModeActive: ui.planModeActive, autoApproveEdits: ui.autoApproveEdits, backgroundTasksRunning: ui.backgroundTasksRunning }), _jsx(BackgroundTasksPanel, { tasks: ui.backgroundTasks, isExpanded: ui.backgroundTasksExpanded, isProcessing: ui.isProcessing }), _jsx(TodoPanel, { todos: todos, isExpanded: ui.todoExpanded, isProcessing: ui.isProcessing }), selectionHintVisible && (_jsx(Box, { paddingX: 1, children: _jsx(Text, { color: "yellowBright", children: "\uD83D\uDCA1 Tip: Hold Option (\u2325) and click to select text, or press Ctrl+S to toggle copy mode" }) })), _jsx(QueuedMessagesDisplay, { messages: queuedMessages }), _jsx(InputContainer, { ref: inputContainerRef, buffer: buffer, input: input, ui: ui, session: session, approval: approval, queuedMessages: queuedMessages, setInput: setInput, setUi: setUi, setSession: setSession, setMessages: setMessages, setPendingMessages: setPendingMessages, setDequeuedBuffer: setDequeuedBuffer, setQueuedMessages: setQueuedMessages, setApproval: setApproval, setApprovalQueue: setApprovalQueue, setTodos: setTodos, agent: agent, inputService: inputService, onKeyboardScroll: handleKeyboardScroll, useStreaming: useStreaming }), _jsx(OverlayContainer, { ref: overlayContainerRef, ui: ui, input: input, session: session, approval: approval, setInput: setInput, setUi: setUi, setSession: setSession, setMessages: setMessages, setApproval: setApproval, setApprovalQueue: setApprovalQueue, agent: agent, inputService: inputService, buffer: buffer, onSubmitPromptCommand: handleSubmitPromptCommand }), ui.exitWarningShown && (_jsxs(Box, { paddingX: 1, children: [_jsx(Text, { color: "yellowBright", bold: true, children: "\u26A0 Press Ctrl+C again to exit" }), _jsx(Text, { color: "gray", children: " (or press any key to cancel)" })] })), _jsx(Footer, { agent: agent, sessionId: session.id, modelName: session.modelName, cwd: process.cwd(), ...(branchName ? { branchName } : {}), autoApproveEdits: ui.autoApproveEdits, planModeActive: ui.planModeActive, isShellMode: buffer.text.startsWith('!') }), ui.historySearch.isActive && (_jsx(HistorySearchBar, { query: ui.historySearch.query, hasMatch: historySearchHasMatch }))] })] }));
|
|
179
180
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StaticCLI.d.ts","sourceRoot":"","sources":["../../../../../src/cli/ink-cli/components/modes/StaticCLI.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAM9C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"StaticCLI.d.ts","sourceRoot":"","sources":["../../../../../src/cli/ink-cli/components/modes/StaticCLI.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAM9C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAqBxD,UAAU,cAAc;IACpB,KAAK,EAAE,UAAU,CAAC;IAClB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,WAAW,EAAE,WAAW,CAAC;IACzB,6DAA6D;IAC7D,YAAY,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,wBAAgB,SAAS,CAAC,EACtB,KAAK,EACL,gBAAgB,EAChB,WAAW,EACX,YAAmB,GACtB,EAAE,cAAc,2CAmPhB"}
|