dexto 1.5.0 → 1.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/commands/interactive-commands/command-parser.d.ts +1 -1
- package/dist/cli/commands/interactive-commands/command-parser.d.ts.map +1 -1
- package/dist/cli/commands/interactive-commands/command-parser.js +11 -1
- package/dist/cli/commands/interactive-commands/general-commands.d.ts.map +1 -1
- package/dist/cli/commands/interactive-commands/general-commands.js +63 -0
- package/dist/cli/commands/interactive-commands/system/system-commands.d.ts.map +1 -1
- package/dist/cli/commands/interactive-commands/system/system-commands.js +3 -2
- package/dist/cli/commands/setup.d.ts.map +1 -1
- package/dist/cli/commands/setup.js +163 -28
- package/dist/cli/ink-cli/components/ResourceAutocomplete.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/ResourceAutocomplete.js +8 -2
- package/dist/cli/ink-cli/components/TextBufferInput.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/TextBufferInput.js +24 -6
- package/dist/cli/ink-cli/components/chat/Header.js +1 -1
- package/dist/cli/ink-cli/components/chat/MessageItem.d.ts +3 -1
- package/dist/cli/ink-cli/components/chat/MessageItem.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/chat/MessageItem.js +37 -10
- package/dist/cli/ink-cli/components/chat/styled-boxes/LogConfigBox.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/chat/styled-boxes/LogConfigBox.js +1 -1
- package/dist/cli/ink-cli/components/modes/AlternateBufferCLI.js +3 -3
- package/dist/cli/ink-cli/components/modes/StaticCLI.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/modes/StaticCLI.js +10 -3
- package/dist/cli/ink-cli/components/overlays/CustomModelWizard.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/overlays/CustomModelWizard.js +19 -8
- package/dist/cli/ink-cli/components/overlays/LogLevelSelector.js +1 -1
- package/dist/cli/ink-cli/components/overlays/ModelSelectorRefactored.d.ts +2 -1
- package/dist/cli/ink-cli/components/overlays/ModelSelectorRefactored.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/overlays/ModelSelectorRefactored.js +64 -2
- 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 +44 -1
- package/dist/cli/ink-cli/components/overlays/custom-model-wizard/types.d.ts +6 -0
- package/dist/cli/ink-cli/components/overlays/custom-model-wizard/types.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/renderers/GenericRenderer.js +1 -1
- package/dist/cli/ink-cli/components/renderers/SearchRenderer.js +1 -1
- package/dist/cli/ink-cli/components/shared/MarkdownText.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/shared/MarkdownText.js +4 -4
- package/dist/cli/ink-cli/constants/processingPhrases.d.ts.map +1 -1
- package/dist/cli/ink-cli/constants/processingPhrases.js +58 -48
- package/dist/cli/ink-cli/constants/tips.d.ts.map +1 -1
- package/dist/cli/ink-cli/constants/tips.js +33 -32
- package/dist/cli/ink-cli/containers/InputContainer.d.ts.map +1 -1
- package/dist/cli/ink-cli/containers/InputContainer.js +18 -11
- package/dist/cli/ink-cli/containers/OverlayContainer.d.ts.map +1 -1
- package/dist/cli/ink-cli/containers/OverlayContainer.js +26 -3
- package/dist/cli/ink-cli/hooks/useAgentEvents.d.ts +8 -1
- package/dist/cli/ink-cli/hooks/useAgentEvents.d.ts.map +1 -1
- package/dist/cli/ink-cli/hooks/useAgentEvents.js +144 -6
- package/dist/cli/ink-cli/hooks/useCLIState.d.ts.map +1 -1
- package/dist/cli/ink-cli/hooks/useCLIState.js +17 -1
- package/dist/cli/ink-cli/hooks/useTokenCounter.d.ts +11 -7
- package/dist/cli/ink-cli/hooks/useTokenCounter.d.ts.map +1 -1
- package/dist/cli/ink-cli/hooks/useTokenCounter.js +41 -18
- package/dist/cli/ink-cli/services/processStream.d.ts.map +1 -1
- package/dist/cli/ink-cli/services/processStream.js +20 -8
- package/dist/cli/ink-cli/state/types.d.ts +2 -2
- package/dist/cli/ink-cli/state/types.d.ts.map +1 -1
- package/dist/cli/ink-cli/utils/messageFormatting.d.ts.map +1 -1
- package/dist/cli/ink-cli/utils/messageFormatting.js +92 -5
- package/dist/index.js +24 -3
- package/package.json +7 -7
|
@@ -31,7 +31,7 @@ export interface CommandDefinition {
|
|
|
31
31
|
handler: (args: string[], agent: DextoAgent, ctx: CommandContext) => Promise<CommandHandlerResult>;
|
|
32
32
|
}
|
|
33
33
|
/**
|
|
34
|
-
* Parses user input to determine if it's a slash command or
|
|
34
|
+
* Parses user input to determine if it's a slash command, shell command, or regular prompt
|
|
35
35
|
*/
|
|
36
36
|
export declare function parseInput(input: string): CommandResult;
|
|
37
37
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"command-parser.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/interactive-commands/command-parser.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,KAAK,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,0CAA0C,CAAC;AAEhG,MAAM,WAAW,aAAa;IAC1B,IAAI,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;GAMG;AACH,MAAM,MAAM,oBAAoB,GAAG,OAAO,GAAG,MAAM,GAAG,YAAY,GAAG,iBAAiB,CAAC;AAEvF;;GAEG;AACH,MAAM,WAAW,cAAc;IAC3B,uDAAuD;IACvD,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED,MAAM,WAAW,iBAAiB;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,WAAW,CAAC,EAAE,iBAAiB,EAAE,CAAC;IAClC,OAAO,EAAE,CACL,IAAI,EAAE,MAAM,EAAE,EACd,KAAK,EAAE,UAAU,EACjB,GAAG,EAAE,cAAc,KAClB,OAAO,CAAC,oBAAoB,CAAC,CAAC;CACtC;AA4CD;;GAEG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,aAAa,
|
|
1
|
+
{"version":3,"file":"command-parser.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/interactive-commands/command-parser.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,KAAK,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,0CAA0C,CAAC;AAEhG,MAAM,WAAW,aAAa;IAC1B,IAAI,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;GAMG;AACH,MAAM,MAAM,oBAAoB,GAAG,OAAO,GAAG,MAAM,GAAG,YAAY,GAAG,iBAAiB,CAAC;AAEvF;;GAEG;AACH,MAAM,WAAW,cAAc;IAC3B,uDAAuD;IACvD,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED,MAAM,WAAW,iBAAiB;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,WAAW,CAAC,EAAE,iBAAiB,EAAE,CAAC;IAClC,OAAO,EAAE,CACL,IAAI,EAAE,MAAM,EAAE,EACd,KAAK,EAAE,UAAU,EACjB,GAAG,EAAE,cAAc,KAClB,OAAO,CAAC,oBAAoB,CAAC,CAAC;CACtC;AA4CD;;GAEG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,aAAa,CAiCvD;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,iBAAiB,EAAE,GAAG,MAAM,EAAE,CAoB9F;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,iBAAiB,EAAE,QAAQ,GAAE,OAAe,GAAG,MAAM,CAmB3F;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,iBAAiB,EAAE,GAAG,IAAI,CAuDtE"}
|
|
@@ -41,10 +41,20 @@ function parseQuotedArguments(input) {
|
|
|
41
41
|
return args.filter((arg) => arg.length > 0);
|
|
42
42
|
}
|
|
43
43
|
/**
|
|
44
|
-
* Parses user input to determine if it's a slash command or
|
|
44
|
+
* Parses user input to determine if it's a slash command, shell command, or regular prompt
|
|
45
45
|
*/
|
|
46
46
|
export function parseInput(input) {
|
|
47
47
|
const trimmed = input.trim();
|
|
48
|
+
// Check if it's a shell command (! prefix)
|
|
49
|
+
if (trimmed.startsWith('!')) {
|
|
50
|
+
const shellCommand = trimmed.slice(1).trim();
|
|
51
|
+
return {
|
|
52
|
+
type: 'command',
|
|
53
|
+
command: 'shell',
|
|
54
|
+
args: [shellCommand],
|
|
55
|
+
rawInput: trimmed,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
48
58
|
// Check if it's a slash command
|
|
49
59
|
if (trimmed.startsWith('/')) {
|
|
50
60
|
const args = parseQuotedArguments(trimmed.slice(1));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"general-commands.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/interactive-commands/general-commands.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;
|
|
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;AAiDnG;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,cAAc,EAAE,MAAM,iBAAiB,EAAE,GAAG,iBAAiB,CAgC9F;AAED;;;GAGG;AACH,eAAO,MAAM,eAAe,EAAE,iBAAiB,EAyO9C,CAAC"}
|
|
@@ -10,9 +10,42 @@
|
|
|
10
10
|
* - /clear, /reset - Clear conversation history
|
|
11
11
|
*/
|
|
12
12
|
import chalk from 'chalk';
|
|
13
|
+
import { spawn } from 'child_process';
|
|
13
14
|
import { formatForInkCli } from './utils/format-output.js';
|
|
14
15
|
import { CommandOutputHelper } from './utils/command-output.js';
|
|
15
16
|
import { writeToClipboard } from '../../ink-cli/utils/clipboardUtils.js';
|
|
17
|
+
/**
|
|
18
|
+
* Execute a shell command and return the output
|
|
19
|
+
*/
|
|
20
|
+
async function executeShellCommand(command, cwd, timeoutMs = 30000) {
|
|
21
|
+
return new Promise((resolve) => {
|
|
22
|
+
const child = spawn(command, [], {
|
|
23
|
+
cwd,
|
|
24
|
+
shell: true,
|
|
25
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
26
|
+
});
|
|
27
|
+
let stdout = '';
|
|
28
|
+
let stderr = '';
|
|
29
|
+
const timer = setTimeout(() => {
|
|
30
|
+
child.kill();
|
|
31
|
+
resolve({ stdout, stderr: `Command timed out after ${timeoutMs}ms`, exitCode: -1 });
|
|
32
|
+
}, timeoutMs);
|
|
33
|
+
child.stdout.on('data', (data) => {
|
|
34
|
+
stdout += data.toString();
|
|
35
|
+
});
|
|
36
|
+
child.stderr.on('data', (data) => {
|
|
37
|
+
stderr += data.toString();
|
|
38
|
+
});
|
|
39
|
+
child.on('error', (error) => {
|
|
40
|
+
clearTimeout(timer);
|
|
41
|
+
resolve({ stdout, stderr: error.message, exitCode: -1 });
|
|
42
|
+
});
|
|
43
|
+
child.on('close', (code) => {
|
|
44
|
+
clearTimeout(timer);
|
|
45
|
+
resolve({ stdout, stderr, exitCode: code ?? -1 });
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
}
|
|
16
49
|
/**
|
|
17
50
|
* Creates the help command with access to all commands for display
|
|
18
51
|
*/
|
|
@@ -47,6 +80,36 @@ export function createHelpCommand(getAllCommands) {
|
|
|
47
80
|
* Note: The help command is created separately to avoid circular dependencies
|
|
48
81
|
*/
|
|
49
82
|
export const generalCommands = [
|
|
83
|
+
{
|
|
84
|
+
name: 'shell',
|
|
85
|
+
description: 'Execute shell command directly (use !command as shortcut)',
|
|
86
|
+
usage: '!<command> or /shell <command>',
|
|
87
|
+
category: 'General',
|
|
88
|
+
handler: async (args, agent, _ctx) => {
|
|
89
|
+
const command = args.join(' ').trim();
|
|
90
|
+
if (!command) {
|
|
91
|
+
return formatForInkCli('❌ No command provided. Usage: !<command>');
|
|
92
|
+
}
|
|
93
|
+
const cwd = process.cwd();
|
|
94
|
+
agent.logger.debug(`Executing shell command: ${command}`);
|
|
95
|
+
const { stdout, stderr, exitCode } = await executeShellCommand(command, cwd);
|
|
96
|
+
// Build output
|
|
97
|
+
const lines = [];
|
|
98
|
+
if (stdout.trim()) {
|
|
99
|
+
lines.push(stdout.trim());
|
|
100
|
+
}
|
|
101
|
+
if (stderr.trim()) {
|
|
102
|
+
lines.push(chalk.yellow(stderr.trim()));
|
|
103
|
+
}
|
|
104
|
+
if (exitCode !== 0) {
|
|
105
|
+
lines.push(chalk.red(`Exit code: ${exitCode}`));
|
|
106
|
+
}
|
|
107
|
+
if (lines.length === 0) {
|
|
108
|
+
return formatForInkCli(chalk.gray('(no output)'));
|
|
109
|
+
}
|
|
110
|
+
return formatForInkCli(lines.join('\n'));
|
|
111
|
+
},
|
|
112
|
+
},
|
|
50
113
|
{
|
|
51
114
|
name: 'exit',
|
|
52
115
|
description: 'Exit the CLI',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"system-commands.d.ts","sourceRoot":"","sources":["../../../../../src/cli/commands/interactive-commands/system/system-commands.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,OAAO,KAAK,EAAE,iBAAiB,EAAwC,MAAM,sBAAsB,CAAC;AAKpG;;GAEG;AACH,eAAO,MAAM,cAAc,EAAE,iBAAiB,
|
|
1
|
+
{"version":3,"file":"system-commands.d.ts","sourceRoot":"","sources":["../../../../../src/cli/commands/interactive-commands/system/system-commands.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,OAAO,KAAK,EAAE,iBAAiB,EAAwC,MAAM,sBAAsB,CAAC;AAKpG;;GAEG;AACH,eAAO,MAAM,cAAc,EAAE,iBAAiB,EAyO7C,CAAC"}
|
|
@@ -33,7 +33,7 @@ export const systemCommands = [
|
|
|
33
33
|
const logFilePath = logger.getLogFilePath();
|
|
34
34
|
console.log(chalk.bold.blue('\n📊 Logging Configuration:\n'));
|
|
35
35
|
console.log(` Current level: ${chalk.green.bold(currentLevel)}`);
|
|
36
|
-
if (logFilePath) {
|
|
36
|
+
if (logFilePath && process.env.DEXTO_PRIVACY_MODE !== 'true') {
|
|
37
37
|
console.log(` Log file: ${chalk.cyan(logFilePath)}`);
|
|
38
38
|
}
|
|
39
39
|
console.log(chalk.gray('\n Available levels (from least to most verbose):'));
|
|
@@ -44,10 +44,11 @@ export const systemCommands = [
|
|
|
44
44
|
console.log(` ${marker} ${levelText}`);
|
|
45
45
|
});
|
|
46
46
|
console.log(chalk.gray('\n 💡 Use /log <level> to change level (e.g., /log debug)\n'));
|
|
47
|
+
const isPrivacyMode = process.env.DEXTO_PRIVACY_MODE === 'true';
|
|
47
48
|
const output = [
|
|
48
49
|
'\n📊 Logging Configuration:',
|
|
49
50
|
`Current level: ${currentLevel}`,
|
|
50
|
-
logFilePath ? `Log file: ${logFilePath}` : '',
|
|
51
|
+
logFilePath && !isPrivacyMode ? `Log file: ${logFilePath}` : '',
|
|
51
52
|
'\nAvailable levels: error, warn, info, http, verbose, debug, silly',
|
|
52
53
|
'💡 Use /log <level> to change level',
|
|
53
54
|
]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/setup.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/setup.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AA2CxB,QAAA,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA0ClB,CAAC;AAEP,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAClE,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAsHtE;;GAEG;AACH,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,OAAO,CAAC,oBAAoB,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAmC9F"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// packages/cli/src/cli/commands/setup.ts
|
|
2
2
|
import chalk from 'chalk';
|
|
3
3
|
import { z } from 'zod';
|
|
4
|
-
import { getDefaultModelForProvider, LLM_PROVIDERS, LLM_REGISTRY, isValidProviderModel, getSupportedModels, acceptsAnyModel, supportsCustomModels, requiresApiKey, } from '@dexto/core';
|
|
4
|
+
import { getDefaultModelForProvider, LLM_PROVIDERS, LLM_REGISTRY, isValidProviderModel, getSupportedModels, acceptsAnyModel, supportsCustomModels, requiresApiKey, isReasoningCapableModel, } from '@dexto/core';
|
|
5
5
|
import { resolveApiKeyForProvider } from '@dexto/core';
|
|
6
6
|
import { createInitialPreferences, saveGlobalPreferences, loadGlobalPreferences, getGlobalPreferencesPath, updateGlobalPreferences, setActiveModel, } from '@dexto/agent-management';
|
|
7
7
|
import { interactiveApiKeySetup, hasApiKeyConfigured } from '../utils/api-key-setup.js';
|
|
@@ -56,34 +56,44 @@ const SetupCommandSchema = z
|
|
|
56
56
|
}
|
|
57
57
|
});
|
|
58
58
|
/**
|
|
59
|
-
* Get the steps to display for the current provider.
|
|
60
|
-
* Local/Ollama providers skip the API Key step.
|
|
59
|
+
* Get the steps to display for the current provider and model.
|
|
60
|
+
* - Local/Ollama providers skip the API Key step.
|
|
61
|
+
* - Reasoning-capable models (o1, o3, codex, gpt-5.x) show the Reasoning step.
|
|
61
62
|
*/
|
|
62
|
-
function getWizardSteps(provider) {
|
|
63
|
+
function getWizardSteps(provider, model) {
|
|
63
64
|
const isLocalProvider = provider === 'local' || provider === 'ollama';
|
|
65
|
+
const showReasoningStep = model && isReasoningCapableModel(model);
|
|
64
66
|
if (isLocalProvider) {
|
|
65
|
-
|
|
67
|
+
const steps = [
|
|
66
68
|
{ key: 'provider', label: 'Provider' },
|
|
67
69
|
{ key: 'model', label: 'Model' },
|
|
68
|
-
{ key: 'mode', label: 'Mode' },
|
|
69
70
|
];
|
|
71
|
+
if (showReasoningStep) {
|
|
72
|
+
steps.push({ key: 'reasoningEffort', label: 'Reasoning' });
|
|
73
|
+
}
|
|
74
|
+
steps.push({ key: 'mode', label: 'Mode' });
|
|
75
|
+
return steps;
|
|
70
76
|
}
|
|
71
|
-
|
|
77
|
+
const steps = [
|
|
72
78
|
{ key: 'provider', label: 'Provider' },
|
|
73
79
|
{ key: 'model', label: 'Model' },
|
|
74
|
-
{ key: 'apiKey', label: 'API Key' },
|
|
75
|
-
{ key: 'mode', label: 'Mode' },
|
|
76
80
|
];
|
|
81
|
+
if (showReasoningStep) {
|
|
82
|
+
steps.push({ key: 'reasoningEffort', label: 'Reasoning' });
|
|
83
|
+
}
|
|
84
|
+
steps.push({ key: 'apiKey', label: 'API Key' });
|
|
85
|
+
steps.push({ key: 'mode', label: 'Mode' });
|
|
86
|
+
return steps;
|
|
77
87
|
}
|
|
78
88
|
/**
|
|
79
89
|
* Display step progress indicator for the setup wizard
|
|
80
90
|
*/
|
|
81
|
-
function showStepProgress(currentStep, provider) {
|
|
91
|
+
function showStepProgress(currentStep, provider, model) {
|
|
82
92
|
// Don't show progress for setupType (it's the entry point)
|
|
83
93
|
if (currentStep === 'setupType' || currentStep === 'complete') {
|
|
84
94
|
return;
|
|
85
95
|
}
|
|
86
|
-
const steps = getWizardSteps(provider);
|
|
96
|
+
const steps = getWizardSteps(provider, model);
|
|
87
97
|
const currentIndex = steps.findIndex((s) => s.key === currentStep);
|
|
88
98
|
if (currentIndex === -1) {
|
|
89
99
|
return;
|
|
@@ -226,6 +236,9 @@ async function handleInteractiveSetup(_options) {
|
|
|
226
236
|
case 'model':
|
|
227
237
|
state = await wizardStepModel(state);
|
|
228
238
|
break;
|
|
239
|
+
case 'reasoningEffort':
|
|
240
|
+
state = await wizardStepReasoningEffort(state);
|
|
241
|
+
break;
|
|
229
242
|
case 'apiKey':
|
|
230
243
|
state = await wizardStepApiKey(state);
|
|
231
244
|
break;
|
|
@@ -299,8 +312,10 @@ async function wizardStepModel(state) {
|
|
|
299
312
|
if (!hasSelectedModel(localResult)) {
|
|
300
313
|
return { ...state, step: 'provider', model: undefined };
|
|
301
314
|
}
|
|
302
|
-
|
|
303
|
-
|
|
315
|
+
const model = getModelFromResult(localResult);
|
|
316
|
+
// Check if model supports reasoning effort
|
|
317
|
+
const nextStep = isReasoningCapableModel(model) ? 'reasoningEffort' : 'mode';
|
|
318
|
+
return { ...state, step: nextStep, model };
|
|
304
319
|
}
|
|
305
320
|
if (provider === 'ollama') {
|
|
306
321
|
const ollamaResult = await setupOllamaModels();
|
|
@@ -308,8 +323,10 @@ async function wizardStepModel(state) {
|
|
|
308
323
|
if (!hasSelectedModel(ollamaResult)) {
|
|
309
324
|
return { ...state, step: 'provider', model: undefined };
|
|
310
325
|
}
|
|
311
|
-
|
|
312
|
-
|
|
326
|
+
const model = getModelFromResult(ollamaResult);
|
|
327
|
+
// Check if model supports reasoning effort
|
|
328
|
+
const nextStep = isReasoningCapableModel(model) ? 'reasoningEffort' : 'mode';
|
|
329
|
+
return { ...state, step: nextStep, model };
|
|
313
330
|
}
|
|
314
331
|
// Handle baseURL for providers that need it
|
|
315
332
|
let baseURL;
|
|
@@ -326,7 +343,52 @@ async function wizardStepModel(state) {
|
|
|
326
343
|
if (model === '_back') {
|
|
327
344
|
return { ...state, step: 'provider', model: undefined, baseURL: undefined };
|
|
328
345
|
}
|
|
329
|
-
|
|
346
|
+
// Check if model supports reasoning effort
|
|
347
|
+
const nextStep = isReasoningCapableModel(model) ? 'reasoningEffort' : 'apiKey';
|
|
348
|
+
return { ...state, step: nextStep, model, baseURL };
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* Wizard Step: Reasoning Effort Selection (for OpenAI reasoning models)
|
|
352
|
+
*/
|
|
353
|
+
async function wizardStepReasoningEffort(state) {
|
|
354
|
+
const provider = state.provider;
|
|
355
|
+
const model = state.model;
|
|
356
|
+
const isLocalProvider = provider === 'local' || provider === 'ollama';
|
|
357
|
+
showStepProgress('reasoningEffort', provider, model);
|
|
358
|
+
const result = await p.select({
|
|
359
|
+
message: 'Select reasoning effort level',
|
|
360
|
+
options: [
|
|
361
|
+
{
|
|
362
|
+
value: 'medium',
|
|
363
|
+
label: 'Medium (Recommended)',
|
|
364
|
+
hint: 'Balanced reasoning for most tasks',
|
|
365
|
+
},
|
|
366
|
+
{ value: 'low', label: 'Low', hint: 'Light reasoning, fast responses' },
|
|
367
|
+
{
|
|
368
|
+
value: 'minimal',
|
|
369
|
+
label: 'Minimal',
|
|
370
|
+
hint: 'Barely any reasoning, very fast',
|
|
371
|
+
},
|
|
372
|
+
{ value: 'high', label: 'High', hint: 'More thorough reasoning' },
|
|
373
|
+
{
|
|
374
|
+
value: 'xhigh',
|
|
375
|
+
label: 'Extra High',
|
|
376
|
+
hint: 'Maximum reasoning, slower responses',
|
|
377
|
+
},
|
|
378
|
+
{ value: 'none', label: 'None', hint: 'Disable reasoning' },
|
|
379
|
+
{ value: '_back', label: chalk.gray('← Back'), hint: 'Change model' },
|
|
380
|
+
],
|
|
381
|
+
});
|
|
382
|
+
if (p.isCancel(result)) {
|
|
383
|
+
p.cancel('Setup cancelled');
|
|
384
|
+
process.exit(0);
|
|
385
|
+
}
|
|
386
|
+
if (result === '_back') {
|
|
387
|
+
return { ...state, step: 'model', reasoningEffort: undefined };
|
|
388
|
+
}
|
|
389
|
+
// Determine next step based on provider type
|
|
390
|
+
const nextStep = isLocalProvider ? 'mode' : 'apiKey';
|
|
391
|
+
return { ...state, step: nextStep, reasoningEffort: result };
|
|
330
392
|
}
|
|
331
393
|
/**
|
|
332
394
|
* Wizard Step: API Key Configuration
|
|
@@ -334,7 +396,7 @@ async function wizardStepModel(state) {
|
|
|
334
396
|
async function wizardStepApiKey(state) {
|
|
335
397
|
const provider = state.provider;
|
|
336
398
|
const model = state.model;
|
|
337
|
-
showStepProgress('apiKey', provider);
|
|
399
|
+
showStepProgress('apiKey', provider, model);
|
|
338
400
|
const hasKey = hasApiKeyConfigured(provider);
|
|
339
401
|
const needsApiKey = requiresApiKey(provider);
|
|
340
402
|
if (needsApiKey && !hasKey) {
|
|
@@ -343,8 +405,9 @@ async function wizardStepApiKey(state) {
|
|
|
343
405
|
model,
|
|
344
406
|
});
|
|
345
407
|
if (result.cancelled) {
|
|
346
|
-
// Go back to model selection
|
|
347
|
-
|
|
408
|
+
// Go back to reasoning effort if model supports it, otherwise model selection
|
|
409
|
+
const prevStep = isReasoningCapableModel(model) ? 'reasoningEffort' : 'model';
|
|
410
|
+
return { ...state, step: prevStep, apiKeySkipped: undefined };
|
|
348
411
|
}
|
|
349
412
|
const apiKeySkipped = result.skipped || !result.success;
|
|
350
413
|
return { ...state, step: 'mode', apiKeySkipped };
|
|
@@ -362,14 +425,22 @@ async function wizardStepApiKey(state) {
|
|
|
362
425
|
*/
|
|
363
426
|
async function wizardStepMode(state) {
|
|
364
427
|
const provider = state.provider;
|
|
428
|
+
const model = state.model;
|
|
365
429
|
const isLocalProvider = provider === 'local' || provider === 'ollama';
|
|
366
|
-
|
|
430
|
+
const hasReasoningStep = isReasoningCapableModel(model);
|
|
431
|
+
showStepProgress('mode', provider, model);
|
|
367
432
|
const mode = await selectDefaultModeWithBack();
|
|
368
433
|
if (mode === '_back') {
|
|
369
|
-
// Go back to previous step
|
|
434
|
+
// Go back to previous step based on provider type and model capabilities
|
|
370
435
|
if (isLocalProvider) {
|
|
371
|
-
|
|
436
|
+
// Local: reasoning effort -> model
|
|
437
|
+
return {
|
|
438
|
+
...state,
|
|
439
|
+
step: hasReasoningStep ? 'reasoningEffort' : 'model',
|
|
440
|
+
defaultMode: undefined,
|
|
441
|
+
};
|
|
372
442
|
}
|
|
443
|
+
// Cloud: always go back to apiKey (reasoning effort comes before apiKey)
|
|
373
444
|
return { ...state, step: 'apiKey', defaultMode: undefined };
|
|
374
445
|
}
|
|
375
446
|
return { ...state, step: 'complete', defaultMode: mode };
|
|
@@ -472,6 +543,9 @@ async function saveWizardPreferences(state) {
|
|
|
472
543
|
if (state.baseURL) {
|
|
473
544
|
preferencesOptions.baseURL = state.baseURL;
|
|
474
545
|
}
|
|
546
|
+
if (state.reasoningEffort) {
|
|
547
|
+
preferencesOptions.reasoningEffort = state.reasoningEffort;
|
|
548
|
+
}
|
|
475
549
|
const preferences = createInitialPreferences(preferencesOptions);
|
|
476
550
|
await saveGlobalPreferences(preferences);
|
|
477
551
|
// Analytics
|
|
@@ -544,6 +618,9 @@ async function showSettingsMenu() {
|
|
|
544
618
|
...(currentPrefs.llm.baseURL
|
|
545
619
|
? [`Base URL: ${chalk.cyan(currentPrefs.llm.baseURL)}`]
|
|
546
620
|
: []),
|
|
621
|
+
...(currentPrefs.llm.reasoningEffort
|
|
622
|
+
? [`Reasoning Effort: ${chalk.cyan(currentPrefs.llm.reasoningEffort)}`]
|
|
623
|
+
: []),
|
|
547
624
|
].join('\n');
|
|
548
625
|
p.note(currentConfig, 'Current Configuration');
|
|
549
626
|
}
|
|
@@ -634,9 +711,18 @@ async function changeModel(currentProvider) {
|
|
|
634
711
|
return;
|
|
635
712
|
}
|
|
636
713
|
const model = getModelFromResult(localResult);
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
714
|
+
const llmUpdate = {
|
|
715
|
+
provider,
|
|
716
|
+
model,
|
|
717
|
+
};
|
|
718
|
+
// Ask for reasoning effort if applicable
|
|
719
|
+
if (isReasoningCapableModel(model)) {
|
|
720
|
+
const reasoningEffort = await selectReasoningEffort();
|
|
721
|
+
if (reasoningEffort !== null) {
|
|
722
|
+
llmUpdate.reasoningEffort = reasoningEffort;
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
await updateGlobalPreferences({ llm: llmUpdate });
|
|
640
726
|
p.log.success(`Model changed to ${model}`);
|
|
641
727
|
return;
|
|
642
728
|
}
|
|
@@ -648,9 +734,18 @@ async function changeModel(currentProvider) {
|
|
|
648
734
|
return;
|
|
649
735
|
}
|
|
650
736
|
const model = getModelFromResult(ollamaResult);
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
737
|
+
const llmUpdate = {
|
|
738
|
+
provider,
|
|
739
|
+
model,
|
|
740
|
+
};
|
|
741
|
+
// Ask for reasoning effort if applicable
|
|
742
|
+
if (isReasoningCapableModel(model)) {
|
|
743
|
+
const reasoningEffort = await selectReasoningEffort();
|
|
744
|
+
if (reasoningEffort !== null) {
|
|
745
|
+
llmUpdate.reasoningEffort = reasoningEffort;
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
await updateGlobalPreferences({ llm: llmUpdate });
|
|
654
749
|
p.log.success(`Model changed to ${model}`);
|
|
655
750
|
return;
|
|
656
751
|
}
|
|
@@ -671,6 +766,13 @@ async function changeModel(currentProvider) {
|
|
|
671
766
|
if (needsApiKey) {
|
|
672
767
|
llmUpdate.apiKey = `$${apiKeyVar}`;
|
|
673
768
|
}
|
|
769
|
+
// Ask for reasoning effort if applicable
|
|
770
|
+
if (isReasoningCapableModel(model)) {
|
|
771
|
+
const reasoningEffort = await selectReasoningEffort();
|
|
772
|
+
if (reasoningEffort !== null) {
|
|
773
|
+
llmUpdate.reasoningEffort = reasoningEffort;
|
|
774
|
+
}
|
|
775
|
+
}
|
|
674
776
|
await updateGlobalPreferences({ llm: llmUpdate });
|
|
675
777
|
p.log.success(`Model changed to ${model}`);
|
|
676
778
|
}
|
|
@@ -810,6 +912,39 @@ async function selectDefaultMode() {
|
|
|
810
912
|
}
|
|
811
913
|
return mode;
|
|
812
914
|
}
|
|
915
|
+
/**
|
|
916
|
+
* Select reasoning effort level for reasoning-capable models
|
|
917
|
+
* Used in settings menu when changing to a reasoning-capable model
|
|
918
|
+
*/
|
|
919
|
+
async function selectReasoningEffort() {
|
|
920
|
+
const effort = await p.select({
|
|
921
|
+
message: 'Select reasoning effort level',
|
|
922
|
+
options: [
|
|
923
|
+
{
|
|
924
|
+
value: 'medium',
|
|
925
|
+
label: 'Medium (Recommended)',
|
|
926
|
+
hint: 'Balanced reasoning for most tasks',
|
|
927
|
+
},
|
|
928
|
+
{ value: 'low', label: 'Low', hint: 'Light reasoning, fast responses' },
|
|
929
|
+
{
|
|
930
|
+
value: 'minimal',
|
|
931
|
+
label: 'Minimal',
|
|
932
|
+
hint: 'Barely any reasoning, very fast',
|
|
933
|
+
},
|
|
934
|
+
{ value: 'high', label: 'High', hint: 'More thorough reasoning' },
|
|
935
|
+
{
|
|
936
|
+
value: 'xhigh',
|
|
937
|
+
label: 'Extra High',
|
|
938
|
+
hint: 'Maximum reasoning, slower responses',
|
|
939
|
+
},
|
|
940
|
+
{ value: 'none', label: 'None', hint: 'Disable reasoning' },
|
|
941
|
+
],
|
|
942
|
+
});
|
|
943
|
+
if (p.isCancel(effort)) {
|
|
944
|
+
return null;
|
|
945
|
+
}
|
|
946
|
+
return effort;
|
|
947
|
+
}
|
|
813
948
|
/**
|
|
814
949
|
* Select model interactively
|
|
815
950
|
* Returns null if user cancels
|
|
@@ -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;AAEf,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;AAE9C,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;AA6ED;;GAEG;AACH,QAAA,MAAM,yBAAyB,
|
|
1
|
+
{"version":3,"file":"ResourceAutocomplete.d.ts","sourceRoot":"","sources":["../../../../src/cli/ink-cli/components/ResourceAutocomplete.tsx"],"names":[],"mappings":"AAAA,OAAO,KAQN,MAAM,OAAO,CAAC;AAEf,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;AAE9C,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;AA6ED;;GAEG;AACH,QAAA,MAAM,yBAAyB,8GAoQ9B,CAAC;AAEF;;;GAGG;AACH,QAAA,MAAM,oBAAoB,EAErB,OAAO,yBAAyB,CAAC;AAEtC,eAAe,oBAAoB,CAAC"}
|
|
@@ -74,7 +74,7 @@ const ResourceAutocompleteInner = forwardRef(function ResourceAutocomplete({ isV
|
|
|
74
74
|
// Combined state to guarantee single render on navigation
|
|
75
75
|
const [selection, setSelection] = useState({ index: 0, offset: 0 });
|
|
76
76
|
const selectedIndexRef = useRef(0);
|
|
77
|
-
const MAX_VISIBLE_ITEMS =
|
|
77
|
+
const MAX_VISIBLE_ITEMS = 5;
|
|
78
78
|
// Update selection AND scroll offset in a single state update
|
|
79
79
|
// This guarantees exactly one render per navigation action
|
|
80
80
|
const updateSelection = useCallback((indexUpdater) => {
|
|
@@ -122,6 +122,10 @@ const ResourceAutocompleteInner = forwardRef(function ResourceAutocomplete({ isV
|
|
|
122
122
|
cancelled = true;
|
|
123
123
|
};
|
|
124
124
|
}, [isVisible, agent]);
|
|
125
|
+
// NOTE: Auto-close logic is handled synchronously in TextBufferInput.tsx
|
|
126
|
+
// (on backspace deleting @ and on space after @). We don't use useEffect here
|
|
127
|
+
// because React batches state updates, causing race conditions where isVisible
|
|
128
|
+
// and searchQuery update at different times.
|
|
125
129
|
// Extract query from @mention (everything after @)
|
|
126
130
|
const mentionQuery = useMemo(() => {
|
|
127
131
|
// Find the last @ that's at start or after space
|
|
@@ -250,7 +254,9 @@ const ResourceAutocompleteInner = forwardRef(function ResourceAutocomplete({ isV
|
|
|
250
254
|
const uriParts = resource.uri.split('/');
|
|
251
255
|
const displayName = resource.name || uriParts[uriParts.length - 1] || resource.uri;
|
|
252
256
|
const isImage = (resource.mimeType || '').startsWith('image/');
|
|
253
|
-
|
|
257
|
+
// Truncate URI for display (show last 40 chars with ellipsis)
|
|
258
|
+
const truncatedUri = resource.uri.length > 50 ? '…' + resource.uri.slice(-49) : resource.uri;
|
|
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));
|
|
254
260
|
})] }));
|
|
255
261
|
});
|
|
256
262
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TextBufferInput.d.ts","sourceRoot":"","sources":["../../../../src/cli/ink-cli/components/TextBufferInput.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAKH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGnE,+DAA+D;AAC/D,MAAM,MAAM,cAAc,GAAG,oBAAoB,GAAG,uBAAuB,GAAG,OAAO,CAAC;AActF,UAAU,oBAAoB;IAC1B,oCAAoC;IACpC,MAAM,EAAE,UAAU,CAAC;IACnB,+CAA+C;IAC/C,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,kCAAkC;IAClC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,mEAAmE;IACnE,UAAU,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACjC,4DAA4D;IAC5D,iBAAiB,CAAC,EAAE,CAAC,CAAC,SAAS,EAAE,IAAI,GAAG,MAAM,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IACrE,0DAA0D;IAC1D,gBAAgB,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE,cAAc,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IACnE,wCAAwC;IACxC,gBAAgB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC,kDAAkD;IAClD,QAAQ,EAAE,OAAO,CAAC;IAClB,2EAA2E;IAC3E,gBAAgB,CAAC,EAAE,CAAC,CAAC,SAAS,EAAE,IAAI,GAAG,MAAM,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IACpE,oEAAoE;IACpE,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,iDAAiD;IACjD,YAAY,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IAC3D,iEAAiE;IACjE,MAAM,CAAC,EAAE,YAAY,EAAE,GAAG,SAAS,CAAC;IACpC,4DAA4D;IAC5D,aAAa,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IACxD,wDAAwD;IACxD,YAAY,CAAC,EAAE,WAAW,EAAE,GAAG,SAAS,CAAC;IACzC,oEAAoE;IACpE,YAAY,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IAC1D,8DAA8D;IAC9D,kBAAkB,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,WAAW,CAAC,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IAC5F,iEAAiE;IACjE,kBAAkB,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IAC7D,4DAA4D;IAC5D,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACvC;AAuCD,wBAAgB,eAAe,CAAC,EAC5B,MAAM,EACN,QAAQ,EACR,WAAW,EACX,UAAkB,EAClB,iBAAiB,EACjB,gBAAgB,EAChB,gBAAqB,EACrB,QAAQ,EACR,gBAAgB,EAChB,UAAc,EACd,YAAY,EACZ,MAAW,EACX,aAAa,EACb,YAAiB,EACjB,YAAY,EACZ,kBAAkB,EAClB,kBAAkB,EAClB,cAAc,GACjB,EAAE,oBAAoB,
|
|
1
|
+
{"version":3,"file":"TextBufferInput.d.ts","sourceRoot":"","sources":["../../../../src/cli/ink-cli/components/TextBufferInput.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAKH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGnE,+DAA+D;AAC/D,MAAM,MAAM,cAAc,GAAG,oBAAoB,GAAG,uBAAuB,GAAG,OAAO,CAAC;AActF,UAAU,oBAAoB;IAC1B,oCAAoC;IACpC,MAAM,EAAE,UAAU,CAAC;IACnB,+CAA+C;IAC/C,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,kCAAkC;IAClC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,mEAAmE;IACnE,UAAU,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACjC,4DAA4D;IAC5D,iBAAiB,CAAC,EAAE,CAAC,CAAC,SAAS,EAAE,IAAI,GAAG,MAAM,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IACrE,0DAA0D;IAC1D,gBAAgB,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE,cAAc,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IACnE,wCAAwC;IACxC,gBAAgB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC,kDAAkD;IAClD,QAAQ,EAAE,OAAO,CAAC;IAClB,2EAA2E;IAC3E,gBAAgB,CAAC,EAAE,CAAC,CAAC,SAAS,EAAE,IAAI,GAAG,MAAM,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IACpE,oEAAoE;IACpE,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,iDAAiD;IACjD,YAAY,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IAC3D,iEAAiE;IACjE,MAAM,CAAC,EAAE,YAAY,EAAE,GAAG,SAAS,CAAC;IACpC,4DAA4D;IAC5D,aAAa,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IACxD,wDAAwD;IACxD,YAAY,CAAC,EAAE,WAAW,EAAE,GAAG,SAAS,CAAC;IACzC,oEAAoE;IACpE,YAAY,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IAC1D,8DAA8D;IAC9D,kBAAkB,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,WAAW,CAAC,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IAC5F,iEAAiE;IACjE,kBAAkB,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IAC7D,4DAA4D;IAC5D,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACvC;AAuCD,wBAAgB,eAAe,CAAC,EAC5B,MAAM,EACN,QAAQ,EACR,WAAW,EACX,UAAkB,EAClB,iBAAiB,EACjB,gBAAgB,EAChB,gBAAqB,EACrB,QAAQ,EACR,gBAAgB,EAChB,UAAc,EACd,YAAY,EACZ,MAAW,EACX,aAAa,EACb,YAAiB,EACjB,YAAY,EACZ,kBAAkB,EAClB,kBAAkB,EAClB,cAAc,GACjB,EAAE,oBAAoB,2CA0hBtB"}
|
|
@@ -250,14 +250,23 @@ export function TextBufferInput({ buffer, onSubmit, placeholder, isDisabled = fa
|
|
|
250
250
|
buffer.backspace();
|
|
251
251
|
checkRemovedImages();
|
|
252
252
|
checkRemovedPasteBlocks();
|
|
253
|
+
// Check if we should close overlay after backspace
|
|
254
|
+
// NOTE: buffer.text is memoized and won't update until next render,
|
|
255
|
+
// so we calculate the expected new text ourselves
|
|
253
256
|
if (onTriggerOverlay && cursorPos > 0) {
|
|
254
257
|
const deletedChar = prevText[cursorPos - 1];
|
|
255
|
-
|
|
258
|
+
// Calculate what the text will be after backspace
|
|
259
|
+
const expectedNewText = prevText.slice(0, cursorPos - 1) + prevText.slice(cursorPos);
|
|
256
260
|
if (deletedChar === '/' && cursorPos === 1) {
|
|
257
261
|
onTriggerOverlay('close');
|
|
258
262
|
}
|
|
259
|
-
else if (deletedChar === '@'
|
|
260
|
-
|
|
263
|
+
else if (deletedChar === '@') {
|
|
264
|
+
// Close if no valid @ mention remains
|
|
265
|
+
// A valid @ is at start of text or after whitespace
|
|
266
|
+
const hasValidAt = /(^|[\s])@/.test(expectedNewText);
|
|
267
|
+
if (!hasValidAt) {
|
|
268
|
+
onTriggerOverlay('close');
|
|
269
|
+
}
|
|
261
270
|
}
|
|
262
271
|
}
|
|
263
272
|
return;
|
|
@@ -388,6 +397,11 @@ export function TextBufferInput({ buffer, onSubmit, placeholder, isDisabled = fa
|
|
|
388
397
|
else if (key.sequence === '@') {
|
|
389
398
|
onTriggerOverlay('resource-autocomplete');
|
|
390
399
|
}
|
|
400
|
+
else if (/\s/.test(key.sequence)) {
|
|
401
|
+
// Close resource autocomplete when user types whitespace
|
|
402
|
+
// Whitespace means user is done with the mention (either selected or abandoned)
|
|
403
|
+
onTriggerOverlay('close');
|
|
404
|
+
}
|
|
391
405
|
}
|
|
392
406
|
}
|
|
393
407
|
}, [
|
|
@@ -415,6 +429,10 @@ export function TextBufferInput({ buffer, onSubmit, placeholder, isDisabled = fa
|
|
|
415
429
|
const cursorVisualCol = visualCursor[1];
|
|
416
430
|
const separator = '─'.repeat(terminalWidth);
|
|
417
431
|
const totalLines = visualLines.length;
|
|
432
|
+
// Detect shell command mode (input starts with "!")
|
|
433
|
+
const isShellMode = bufferText.startsWith('!');
|
|
434
|
+
const promptPrefix = isShellMode ? '$ ' : '> ';
|
|
435
|
+
const promptColor = isShellMode ? 'yellow' : 'green';
|
|
418
436
|
// Calculate visible window
|
|
419
437
|
let startLine = 0;
|
|
420
438
|
let endLine = totalLines;
|
|
@@ -434,15 +452,15 @@ export function TextBufferInput({ buffer, onSubmit, placeholder, isDisabled = fa
|
|
|
434
452
|
return (_jsxs(Box, { flexDirection: "column", width: terminalWidth, children: [_jsx(Text, { color: "gray", children: separator }), startLine > 0 && (_jsxs(Text, { color: "gray", children: [' ', "\u2191 ", startLine, " more line", startLine > 1 ? 's' : '', " above (", KEY_LABELS.altUp, " to jump)"] })), visibleLines.map((line, idx) => {
|
|
435
453
|
const absoluteRow = startLine + idx;
|
|
436
454
|
const isFirst = absoluteRow === 0;
|
|
437
|
-
const prefix = isFirst ?
|
|
455
|
+
const prefix = isFirst ? promptPrefix : ' ';
|
|
438
456
|
const isCursorLine = absoluteRow === cursorVisualRow;
|
|
439
457
|
if (!isCursorLine) {
|
|
440
|
-
return (_jsxs(Box, { width: terminalWidth, children: [_jsx(Text, { color:
|
|
458
|
+
return (_jsxs(Box, { width: terminalWidth, children: [_jsx(Text, { color: promptColor, bold: isFirst, children: prefix }), _jsx(HighlightedText, { text: line, query: highlightQuery }), _jsx(Text, { children: ' '.repeat(Math.max(0, terminalWidth - prefix.length - line.length)) })] }, absoluteRow));
|
|
441
459
|
}
|
|
442
460
|
const before = line.slice(0, cursorVisualCol);
|
|
443
461
|
const atCursor = line.charAt(cursorVisualCol) || ' ';
|
|
444
462
|
const after = line.slice(cursorVisualCol + 1);
|
|
445
|
-
return (_jsxs(Box, { width: terminalWidth, children: [_jsx(Text, { color:
|
|
463
|
+
return (_jsxs(Box, { width: terminalWidth, children: [_jsx(Text, { color: promptColor, bold: isFirst, children: prefix }), _jsx(HighlightedText, { text: before, query: highlightQuery }), _jsx(Text, { inverse: true, children: atCursor }), _jsx(HighlightedText, { text: after, query: highlightQuery }), _jsx(Text, { children: ' '.repeat(Math.max(0, terminalWidth - prefix.length - before.length - 1 - after.length)) })] }, absoluteRow));
|
|
446
464
|
}), endLine < totalLines && (_jsxs(Text, { color: "gray", children: [' ', "\u2193 ", totalLines - endLine, " more line", totalLines - endLine > 1 ? 's' : '', ' ', "below (", KEY_LABELS.altDown, " to jump)"] })), pastedBlocks.length > 0 && (_jsx(PasteBlockHint, { pastedBlocks: pastedBlocks, expandedBlock: findExpandedBlock(), cursorOnCollapsed: findCollapsedBlockAtCursor() })), _jsx(Text, { color: "gray", children: separator })] }));
|
|
447
465
|
}
|
|
448
466
|
/** Hint component for paste blocks */
|
|
@@ -12,5 +12,5 @@ export function Header({ modelName, sessionId, hasActiveSession, startupInfo })
|
|
|
12
12
|
██║ ██║█████╗ ╚███╔╝ ██║ ██║ ██║
|
|
13
13
|
██║ ██║██╔══╝ ██╔██╗ ██║ ██║ ██║
|
|
14
14
|
██████╔╝███████╗██╔╝ ██╗ ██║ ╚██████╔╝
|
|
15
|
-
╚═════╝ ╚══════╝╚═╝ ╚═╝ ╚═╝ ╚═════╝` }) }), _jsxs(Box, { marginTop: 1, flexDirection: "row", children: [_jsx(Text, { color: "gray", children: "Model: " }), _jsx(Text, { color: "white", children: modelName }), hasActiveSession && sessionId && (_jsxs(_Fragment, { children: [_jsx(Text, { color: "gray", children: " \u2022 Session: " }), _jsx(Text, { color: "white", children: sessionId.slice(0, 8) })] }))] }), _jsxs(Box, { flexDirection: "row", children: [_jsx(Text, { color: "gray", children: "Servers: " }), _jsx(Text, { color: "white", children: startupInfo.connectedServers.count }), _jsx(Text, { color: "gray", children: " \u2022 Tools: " }), _jsx(Text, { color: "white", children: startupInfo.toolCount })] }), startupInfo.failedConnections.length > 0 && (_jsx(Box, { flexDirection: "row", children: _jsxs(Text, { color: "yellowBright", children: ["\u26A0\uFE0F Failed: ", startupInfo.failedConnections.join(', ')] }) })), startupInfo.logFile && (_jsx(Box, { flexDirection: "row", children: _jsxs(Text, { color: "gray", children: ["Logs: ", startupInfo.logFile] }) })), _jsx(Box, { marginBottom: 1, children: _jsx(Text, { children: " " }) })] }));
|
|
15
|
+
╚═════╝ ╚══════╝╚═╝ ╚═╝ ╚═╝ ╚═════╝` }) }), _jsxs(Box, { marginTop: 1, flexDirection: "row", children: [_jsx(Text, { color: "gray", children: "Model: " }), _jsx(Text, { color: "white", children: modelName }), hasActiveSession && sessionId && (_jsxs(_Fragment, { children: [_jsx(Text, { color: "gray", children: " \u2022 Session: " }), _jsx(Text, { color: "white", children: sessionId.slice(0, 8) })] }))] }), _jsxs(Box, { flexDirection: "row", children: [_jsx(Text, { color: "gray", children: "Servers: " }), _jsx(Text, { color: "white", children: startupInfo.connectedServers.count }), _jsx(Text, { color: "gray", children: " \u2022 Tools: " }), _jsx(Text, { color: "white", children: startupInfo.toolCount })] }), startupInfo.failedConnections.length > 0 && (_jsx(Box, { flexDirection: "row", children: _jsxs(Text, { color: "yellowBright", children: ["\u26A0\uFE0F Failed: ", startupInfo.failedConnections.join(', ')] }) })), startupInfo.logFile && process.env.DEXTO_PRIVACY_MODE !== 'true' && (_jsx(Box, { flexDirection: "row", children: _jsxs(Text, { color: "gray", children: ["Logs: ", startupInfo.logFile] }) })), _jsx(Box, { marginBottom: 1, children: _jsx(Text, { children: " " }) })] }));
|
|
16
16
|
}
|
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
import type { Message } from '../../state/types.js';
|
|
7
7
|
interface MessageItemProps {
|
|
8
8
|
message: Message;
|
|
9
|
+
/** Terminal width for proper text wrapping calculations */
|
|
10
|
+
terminalWidth?: number;
|
|
9
11
|
}
|
|
10
12
|
/**
|
|
11
13
|
* Pure presentational component for a single message
|
|
@@ -14,6 +16,6 @@ interface MessageItemProps {
|
|
|
14
16
|
* Memoization with custom comparator prevents re-renders when message array changes
|
|
15
17
|
* but individual message content hasn't changed.
|
|
16
18
|
*/
|
|
17
|
-
export declare const MessageItem: import("react").MemoExoticComponent<({ message }: MessageItemProps) => import("react/jsx-runtime").JSX.Element>;
|
|
19
|
+
export declare const MessageItem: import("react").MemoExoticComponent<({ message, terminalWidth }: MessageItemProps) => import("react/jsx-runtime").JSX.Element>;
|
|
18
20
|
export {};
|
|
19
21
|
//# sourceMappingURL=MessageItem.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MessageItem.d.ts","sourceRoot":"","sources":["../../../../../src/cli/ink-cli/components/chat/MessageItem.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;
|
|
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,6CA+LrD,CAAC"}
|