aiexecode 1.0.66 → 1.0.69
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.
Potentially problematic release.
This version of aiexecode might be problematic. Click here for more details.
- package/config_template/settings.json +1 -3
- package/index.js +46 -71
- package/package.json +1 -12
- package/payload_viewer/out/404/index.html +1 -1
- package/payload_viewer/out/404.html +1 -1
- package/payload_viewer/out/index.html +1 -1
- package/payload_viewer/out/index.txt +1 -1
- package/payload_viewer/web_server.js +0 -163
- package/prompts/completion_judge.txt +11 -7
- package/src/ai_based/completion_judge.js +97 -6
- package/src/ai_based/orchestrator.js +71 -3
- package/src/ai_based/pip_package_installer.js +14 -12
- package/src/ai_based/pip_package_lookup.js +13 -10
- package/src/commands/apikey.js +8 -34
- package/src/commands/help.js +3 -4
- package/src/commands/model.js +17 -74
- package/src/commands/reasoning_effort.js +1 -1
- package/src/config/feature_flags.js +0 -12
- package/src/{ui → frontend}/App.js +23 -25
- package/src/frontend/README.md +81 -0
- package/src/{ui/components/SuggestionsDisplay.js → frontend/components/AutocompleteMenu.js} +3 -3
- package/src/{ui/components/HistoryItemDisplay.js → frontend/components/ConversationItem.js} +37 -89
- package/src/{ui → frontend}/components/CurrentModelView.js +3 -5
- package/src/{ui → frontend}/components/Footer.js +4 -6
- package/src/{ui → frontend}/components/Header.js +2 -5
- package/src/{ui/components/InputPrompt.js → frontend/components/Input.js} +16 -54
- package/src/frontend/components/ModelListView.js +106 -0
- package/src/{ui → frontend}/components/ModelUpdatedView.js +3 -5
- package/src/{ui → frontend}/components/SessionSpinner.js +3 -3
- package/src/{ui → frontend}/components/SetupWizard.js +8 -101
- package/src/{ui → frontend}/components/ToolApprovalPrompt.js +16 -14
- package/src/frontend/design/themeColors.js +42 -0
- package/src/{ui → frontend}/index.js +7 -7
- package/src/frontend/utils/inputBuffer.js +441 -0
- package/src/{ui/utils/markdownRenderer.js → frontend/utils/markdownParser.js} +3 -3
- package/src/{ui/utils/ConsolePatcher.js → frontend/utils/outputRedirector.js} +9 -9
- package/src/{ui/utils/codeColorizer.js → frontend/utils/syntaxHighlighter.js} +2 -3
- package/src/system/ai_request.js +145 -595
- package/src/system/code_executer.js +111 -16
- package/src/system/file_integrity.js +5 -7
- package/src/system/log.js +3 -3
- package/src/system/mcp_integration.js +15 -13
- package/src/system/output_helper.js +0 -20
- package/src/system/session.js +97 -23
- package/src/system/session_memory.js +2 -82
- package/src/system/system_info.js +1 -1
- package/src/system/ui_events.js +0 -43
- package/src/tools/code_editor.js +17 -2
- package/src/tools/file_reader.js +17 -2
- package/src/tools/glob.js +9 -1
- package/src/tools/response_message.js +0 -2
- package/src/tools/ripgrep.js +9 -1
- package/src/tools/web_downloader.js +9 -1
- package/src/util/config.js +3 -8
- package/src/util/debug_log.js +4 -11
- package/src/util/mcp_config_manager.js +3 -5
- package/src/util/output_formatter.js +0 -47
- package/src/util/prompt_loader.js +3 -4
- package/src/util/safe_fs.js +60 -0
- package/src/util/setup_wizard.js +1 -3
- package/src/util/text_formatter.js +0 -86
- package/src/config/claude_models.js +0 -195
- package/src/ui/README.md +0 -208
- package/src/ui/api.js +0 -167
- package/src/ui/components/AgenticProgressDisplay.js +0 -126
- package/src/ui/components/Composer.js +0 -55
- package/src/ui/components/LoadingIndicator.js +0 -54
- package/src/ui/components/ModelListView.js +0 -214
- package/src/ui/components/Notifications.js +0 -55
- package/src/ui/components/StreamingIndicator.js +0 -36
- package/src/ui/contexts/AppContext.js +0 -25
- package/src/ui/contexts/StreamingContext.js +0 -20
- package/src/ui/contexts/UIStateContext.js +0 -117
- package/src/ui/example-usage.js +0 -180
- package/src/ui/hooks/useTerminalResize.js +0 -39
- package/src/ui/themes/semantic-tokens.js +0 -73
- package/src/ui/utils/text-buffer.js +0 -975
- /package/payload_viewer/out/_next/static/{t0WTsjXST7ISD1Boa6ifx → 7FgHZugvVp3pn1XStUYUJ}/_buildManifest.js +0 -0
- /package/payload_viewer/out/_next/static/{t0WTsjXST7ISD1Boa6ifx → 7FgHZugvVp3pn1XStUYUJ}/_clientMiddlewareManifest.json +0 -0
- /package/payload_viewer/out/_next/static/{t0WTsjXST7ISD1Boa6ifx → 7FgHZugvVp3pn1XStUYUJ}/_ssgManifest.js +0 -0
- /package/src/{ui → frontend}/components/BlankLine.js +0 -0
- /package/src/{ui → frontend}/components/FileDiffViewer.js +0 -0
- /package/src/{ui → frontend}/components/HelpView.js +0 -0
- /package/src/{ui → frontend}/hooks/useCompletion.js +0 -0
- /package/src/{ui → frontend}/hooks/useKeypress.js +0 -0
- /package/src/{ui → frontend}/utils/diffUtils.js +0 -0
- /package/src/{ui → frontend}/utils/renderInkComponent.js +0 -0
|
@@ -1,214 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Model List View Component - Ink-based UI for displaying available models
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import React from 'react';
|
|
6
|
-
import { Box, Text } from 'ink';
|
|
7
|
-
import { theme } from '../themes/semantic-tokens.js';
|
|
8
|
-
|
|
9
|
-
export function ModelListView({ openaiModels, claudeModels }) {
|
|
10
|
-
const sections = [
|
|
11
|
-
// Header
|
|
12
|
-
React.createElement(Box, {
|
|
13
|
-
key: 'header',
|
|
14
|
-
borderStyle: 'double',
|
|
15
|
-
borderColor: 'gray',
|
|
16
|
-
paddingX: 2,
|
|
17
|
-
paddingY: 0,
|
|
18
|
-
justifyContent: 'center'
|
|
19
|
-
},
|
|
20
|
-
React.createElement(Text, {
|
|
21
|
-
bold: true,
|
|
22
|
-
color: 'whiteBright'
|
|
23
|
-
}, 'Available AI Models')
|
|
24
|
-
),
|
|
25
|
-
|
|
26
|
-
React.createElement(Text, { key: 'spacer1' }, null),
|
|
27
|
-
|
|
28
|
-
// OpenAI Section
|
|
29
|
-
React.createElement(Box, {
|
|
30
|
-
key: 'openai-section',
|
|
31
|
-
flexDirection: 'column',
|
|
32
|
-
borderStyle: 'round',
|
|
33
|
-
borderColor: 'gray',
|
|
34
|
-
paddingX: 2,
|
|
35
|
-
paddingY: 1
|
|
36
|
-
},
|
|
37
|
-
React.createElement(Box, { flexDirection: 'column' },
|
|
38
|
-
React.createElement(Text, {
|
|
39
|
-
bold: true,
|
|
40
|
-
color: 'cyan'
|
|
41
|
-
}, '🤖 OpenAI Models'),
|
|
42
|
-
React.createElement(Text, {
|
|
43
|
-
dimColor: true,
|
|
44
|
-
italic: true
|
|
45
|
-
}, 'GPT-5 Series (Latest generation, recommended)'),
|
|
46
|
-
React.createElement(Text, null)
|
|
47
|
-
),
|
|
48
|
-
|
|
49
|
-
openaiModels.map((model, index) =>
|
|
50
|
-
React.createElement(Box, {
|
|
51
|
-
key: model.id,
|
|
52
|
-
flexDirection: 'column',
|
|
53
|
-
marginBottom: index < openaiModels.length - 1 ? 1 : 0
|
|
54
|
-
},
|
|
55
|
-
React.createElement(Box, { flexDirection: 'row', gap: 1 },
|
|
56
|
-
React.createElement(Text, { color: 'green', bold: true }, '•'),
|
|
57
|
-
React.createElement(Text, {
|
|
58
|
-
color: 'white',
|
|
59
|
-
bold: true
|
|
60
|
-
}, model.id)
|
|
61
|
-
),
|
|
62
|
-
React.createElement(Box, {
|
|
63
|
-
flexDirection: 'column',
|
|
64
|
-
marginLeft: 2,
|
|
65
|
-
gap: 0
|
|
66
|
-
},
|
|
67
|
-
React.createElement(Text, {
|
|
68
|
-
color: theme.text.secondary
|
|
69
|
-
}, `${model.name} - ${model.description}`),
|
|
70
|
-
React.createElement(Text, {
|
|
71
|
-
dimColor: true,
|
|
72
|
-
italic: true
|
|
73
|
-
}, `💰 $${model.pricing.input}/$${model.pricing.output} (input/output per 1M tokens)`)
|
|
74
|
-
)
|
|
75
|
-
)
|
|
76
|
-
)
|
|
77
|
-
)
|
|
78
|
-
];
|
|
79
|
-
|
|
80
|
-
// Anthropic 섹션들은 claudeModels가 있을 때만 추가
|
|
81
|
-
if (claudeModels) {
|
|
82
|
-
sections.push(
|
|
83
|
-
React.createElement(Text, { key: 'spacer2' }, null),
|
|
84
|
-
|
|
85
|
-
// Anthropic Claude 4.x Section
|
|
86
|
-
React.createElement(Box, {
|
|
87
|
-
key: 'claude4-section',
|
|
88
|
-
flexDirection: 'column',
|
|
89
|
-
borderStyle: 'round',
|
|
90
|
-
borderColor: 'gray',
|
|
91
|
-
paddingX: 2,
|
|
92
|
-
paddingY: 1
|
|
93
|
-
},
|
|
94
|
-
React.createElement(Box, { flexDirection: 'column' },
|
|
95
|
-
React.createElement(Text, {
|
|
96
|
-
bold: true,
|
|
97
|
-
color: 'magenta'
|
|
98
|
-
}, '🧠 Anthropic Claude Models'),
|
|
99
|
-
React.createElement(Text, {
|
|
100
|
-
dimColor: true,
|
|
101
|
-
italic: true
|
|
102
|
-
}, 'Claude 4.x Series (Latest)'),
|
|
103
|
-
React.createElement(Text, null)
|
|
104
|
-
),
|
|
105
|
-
|
|
106
|
-
claudeModels.claude4.map((model, index) =>
|
|
107
|
-
React.createElement(Box, {
|
|
108
|
-
key: model.id,
|
|
109
|
-
flexDirection: 'column',
|
|
110
|
-
marginBottom: index < claudeModels.claude4.length - 1 ? 1 : 0
|
|
111
|
-
},
|
|
112
|
-
React.createElement(Box, { flexDirection: 'row', gap: 1 },
|
|
113
|
-
React.createElement(Text, { color: 'green', bold: true }, '•'),
|
|
114
|
-
React.createElement(Text, {
|
|
115
|
-
color: 'white',
|
|
116
|
-
bold: true
|
|
117
|
-
}, model.id)
|
|
118
|
-
),
|
|
119
|
-
React.createElement(Box, {
|
|
120
|
-
flexDirection: 'column',
|
|
121
|
-
marginLeft: 2,
|
|
122
|
-
gap: 0
|
|
123
|
-
},
|
|
124
|
-
React.createElement(Text, {
|
|
125
|
-
color: theme.text.secondary
|
|
126
|
-
}, `${model.name} - ${model.description}`),
|
|
127
|
-
React.createElement(Text, {
|
|
128
|
-
dimColor: true,
|
|
129
|
-
italic: true
|
|
130
|
-
}, `💰 $${model.pricing.input}/$${model.pricing.output} (input/output per 1M tokens)`)
|
|
131
|
-
)
|
|
132
|
-
)
|
|
133
|
-
)
|
|
134
|
-
),
|
|
135
|
-
|
|
136
|
-
React.createElement(Text, { key: 'spacer3' }, null),
|
|
137
|
-
|
|
138
|
-
// Claude 3.x Section
|
|
139
|
-
React.createElement(Box, {
|
|
140
|
-
key: 'claude3-section',
|
|
141
|
-
flexDirection: 'column',
|
|
142
|
-
borderStyle: 'round',
|
|
143
|
-
borderColor: 'gray',
|
|
144
|
-
paddingX: 2,
|
|
145
|
-
paddingY: 1
|
|
146
|
-
},
|
|
147
|
-
React.createElement(Box, { flexDirection: 'column' },
|
|
148
|
-
React.createElement(Text, {
|
|
149
|
-
dimColor: true,
|
|
150
|
-
italic: true
|
|
151
|
-
}, 'Claude 3.x Series'),
|
|
152
|
-
React.createElement(Text, null)
|
|
153
|
-
),
|
|
154
|
-
|
|
155
|
-
claudeModels.claude3.map((model, index) =>
|
|
156
|
-
React.createElement(Box, {
|
|
157
|
-
key: model.id,
|
|
158
|
-
flexDirection: 'column',
|
|
159
|
-
marginBottom: index < claudeModels.claude3.length - 1 ? 1 : 0
|
|
160
|
-
},
|
|
161
|
-
React.createElement(Box, { flexDirection: 'row', gap: 1 },
|
|
162
|
-
React.createElement(Text, { color: 'green', bold: true }, '•'),
|
|
163
|
-
React.createElement(Text, {
|
|
164
|
-
color: 'white',
|
|
165
|
-
bold: true
|
|
166
|
-
}, model.id)
|
|
167
|
-
),
|
|
168
|
-
React.createElement(Box, {
|
|
169
|
-
flexDirection: 'column',
|
|
170
|
-
marginLeft: 2,
|
|
171
|
-
gap: 0
|
|
172
|
-
},
|
|
173
|
-
React.createElement(Text, {
|
|
174
|
-
color: theme.text.secondary
|
|
175
|
-
}, `${model.name} - ${model.description}`),
|
|
176
|
-
React.createElement(Text, {
|
|
177
|
-
dimColor: true,
|
|
178
|
-
italic: true
|
|
179
|
-
}, `💰 $${model.pricing.input}/$${model.pricing.output} (input/output per 1M tokens)`)
|
|
180
|
-
)
|
|
181
|
-
)
|
|
182
|
-
)
|
|
183
|
-
)
|
|
184
|
-
);
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
sections.push(
|
|
188
|
-
React.createElement(Text, { key: 'spacer4' }, null),
|
|
189
|
-
|
|
190
|
-
// Footer
|
|
191
|
-
React.createElement(Box, {
|
|
192
|
-
key: 'footer',
|
|
193
|
-
flexDirection: 'column',
|
|
194
|
-
borderStyle: 'single',
|
|
195
|
-
borderColor: 'gray',
|
|
196
|
-
paddingX: 2,
|
|
197
|
-
paddingY: 1
|
|
198
|
-
},
|
|
199
|
-
React.createElement(Text, { bold: true }, '📖 Usage'),
|
|
200
|
-
React.createElement(Text, null, ' /model <model-id>'),
|
|
201
|
-
React.createElement(Text, { dimColor: true }, ' Example: /model gpt-5'),
|
|
202
|
-
React.createElement(Text, null),
|
|
203
|
-
React.createElement(Text, { bold: true }, '🔗 More Info'),
|
|
204
|
-
React.createElement(Text, { color: theme.text.link }, ' OpenAI: https://platform.openai.com/docs/pricing'),
|
|
205
|
-
claudeModels && React.createElement(Text, { color: theme.text.link }, ' Anthropic: https://docs.claude.com/en/docs/about-claude/models/overview')
|
|
206
|
-
)
|
|
207
|
-
);
|
|
208
|
-
|
|
209
|
-
return React.createElement(Box, {
|
|
210
|
-
flexDirection: 'column',
|
|
211
|
-
paddingX: 2,
|
|
212
|
-
paddingY: 1
|
|
213
|
-
}, ...sections);
|
|
214
|
-
}
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Notifications - System notifications and warnings
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import React from 'react';
|
|
6
|
-
import { Box, Text } from 'ink';
|
|
7
|
-
import { theme } from '../themes/semantic-tokens.js';
|
|
8
|
-
import { useUIState, StreamingState } from '../contexts/UIStateContext.js';
|
|
9
|
-
|
|
10
|
-
export function Notifications({ warnings = [], errors = [] }) {
|
|
11
|
-
const uiState = useUIState();
|
|
12
|
-
|
|
13
|
-
// Don't show notifications during streaming to avoid clutter
|
|
14
|
-
if (uiState.streamingState === StreamingState.Responding) {
|
|
15
|
-
return null;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
if (warnings.length === 0 && errors.length === 0) {
|
|
19
|
-
return null;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
return React.createElement(Box, {
|
|
23
|
-
flexDirection: "column",
|
|
24
|
-
marginBottom: 1
|
|
25
|
-
},
|
|
26
|
-
warnings.length > 0 && React.createElement(Box, {
|
|
27
|
-
borderStyle: "round",
|
|
28
|
-
borderColor: theme.status.warning,
|
|
29
|
-
paddingX: 1,
|
|
30
|
-
marginBottom: errors.length > 0 ? 1 : 0,
|
|
31
|
-
flexDirection: "column"
|
|
32
|
-
},
|
|
33
|
-
warnings.map((warning, index) =>
|
|
34
|
-
React.createElement(Text, {
|
|
35
|
-
key: index,
|
|
36
|
-
color: theme.status.warning
|
|
37
|
-
}, '⚠ ' + warning)
|
|
38
|
-
)
|
|
39
|
-
),
|
|
40
|
-
|
|
41
|
-
errors.length > 0 && React.createElement(Box, {
|
|
42
|
-
borderStyle: "round",
|
|
43
|
-
borderColor: theme.status.error,
|
|
44
|
-
paddingX: 1,
|
|
45
|
-
flexDirection: "column"
|
|
46
|
-
},
|
|
47
|
-
errors.map((error, index) =>
|
|
48
|
-
React.createElement(Text, {
|
|
49
|
-
key: index,
|
|
50
|
-
color: theme.status.error
|
|
51
|
-
}, '✗ ' + error)
|
|
52
|
-
)
|
|
53
|
-
)
|
|
54
|
-
);
|
|
55
|
-
}
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* StreamingIndicator - Animated indicator for streaming/processing state
|
|
3
|
-
* Isolated animation to prevent parent re-renders
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import React, { useState, useEffect, memo } from 'react';
|
|
7
|
-
import { Box, Text } from 'ink';
|
|
8
|
-
import { theme } from '../themes/semantic-tokens.js';
|
|
9
|
-
|
|
10
|
-
const SPINNER_FRAMES = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
|
|
11
|
-
const DOTS_FRAMES = ['. ', '.. ', '...', ' '];
|
|
12
|
-
|
|
13
|
-
// Isolated animation component
|
|
14
|
-
const AnimatedFrame = memo(function AnimatedFrame({ type }) {
|
|
15
|
-
const [frameIndex, setFrameIndex] = useState(0);
|
|
16
|
-
|
|
17
|
-
useEffect(() => {
|
|
18
|
-
const frames = type === 'spinner' ? SPINNER_FRAMES : DOTS_FRAMES;
|
|
19
|
-
const interval = setInterval(() => {
|
|
20
|
-
setFrameIndex(prev => (prev + 1) % frames.length);
|
|
21
|
-
}, type === 'spinner' ? 80 : 400);
|
|
22
|
-
|
|
23
|
-
return () => clearInterval(interval);
|
|
24
|
-
}, [type]);
|
|
25
|
-
|
|
26
|
-
const frames = type === 'spinner' ? SPINNER_FRAMES : DOTS_FRAMES;
|
|
27
|
-
return React.createElement(Text, { color: theme.status.info }, frames[frameIndex] + ' ');
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
// Main component
|
|
31
|
-
export const StreamingIndicator = memo(function StreamingIndicator({ message = 'Processing', type = 'spinner' }) {
|
|
32
|
-
return React.createElement(Box, { marginLeft: 2, marginTop: 0 },
|
|
33
|
-
React.createElement(AnimatedFrame, { type }),
|
|
34
|
-
React.createElement(Text, { color: theme.text.secondary }, message)
|
|
35
|
-
);
|
|
36
|
-
});
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* AppContext - Global application state
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import React, { createContext, useContext } from 'react';
|
|
6
|
-
import { createDebugLogger } from '../../util/debug_log.js';
|
|
7
|
-
|
|
8
|
-
const debugLog = createDebugLogger('ui_contexts.log', 'AppContext');
|
|
9
|
-
|
|
10
|
-
const AppContext = createContext(null);
|
|
11
|
-
|
|
12
|
-
export function AppProvider({ children, value }) {
|
|
13
|
-
debugLog('AppProvider initialized');
|
|
14
|
-
return React.createElement(AppContext.Provider, { value }, children);
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export function useAppContext() {
|
|
18
|
-
const context = useContext(AppContext);
|
|
19
|
-
if (!context) {
|
|
20
|
-
debugLog('ERROR: useAppContext called outside AppProvider');
|
|
21
|
-
throw new Error('useAppContext must be used within AppProvider');
|
|
22
|
-
}
|
|
23
|
-
debugLog('useAppContext accessed successfully');
|
|
24
|
-
return context;
|
|
25
|
-
}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* StreamingContext - Real-time streaming state
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import React, { createContext, useContext } from 'react';
|
|
6
|
-
import { createDebugLogger } from '../../util/debug_log.js';
|
|
7
|
-
|
|
8
|
-
const debugLog = createDebugLogger('ui_contexts.log', 'StreamingContext');
|
|
9
|
-
|
|
10
|
-
const StreamingContext = createContext(null);
|
|
11
|
-
|
|
12
|
-
export const StreamingContextProvider = StreamingContext.Provider;
|
|
13
|
-
|
|
14
|
-
export function useStreaming() {
|
|
15
|
-
const context = useContext(StreamingContext);
|
|
16
|
-
debugLog('useStreaming accessed');
|
|
17
|
-
return context;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export { StreamingContext };
|
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* UIStateContext - UI state management
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import React, { createContext, useContext, useState, useRef } from 'react';
|
|
6
|
-
import { createDebugLogger } from '../../util/debug_log.js';
|
|
7
|
-
|
|
8
|
-
const debugLog = createDebugLogger('ui_contexts.log', 'UIStateContext');
|
|
9
|
-
|
|
10
|
-
const UIStateContext = createContext(null);
|
|
11
|
-
|
|
12
|
-
export const StreamingState = {
|
|
13
|
-
Idle: 'idle',
|
|
14
|
-
Responding: 'responding',
|
|
15
|
-
WaitingForConfirmation: 'waiting_for_confirmation',
|
|
16
|
-
Executing: 'executing',
|
|
17
|
-
Completed: 'completed',
|
|
18
|
-
Error: 'error'
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
export function UIStateProvider({ children, initialState = {} }) {
|
|
22
|
-
debugLog(`UIStateProvider initializing - history items: ${(initialState.history || []).length}`);
|
|
23
|
-
|
|
24
|
-
const [history, setHistory] = useState(initialState.history || []);
|
|
25
|
-
const [pendingHistoryItems, setPendingHistoryItems] = useState([]);
|
|
26
|
-
const [streamingState, setStreamingState] = useState(StreamingState.Idle);
|
|
27
|
-
const [currentOperation, setCurrentOperation] = useState(null);
|
|
28
|
-
const [progressMessage, setProgressMessage] = useState('');
|
|
29
|
-
const [thought, setThought] = useState('');
|
|
30
|
-
const [mainAreaWidth, setMainAreaWidth] = useState(process.stdout.columns || 80);
|
|
31
|
-
const [terminalHeight, setTerminalHeight] = useState(process.stdout.rows || 24);
|
|
32
|
-
const [elapsedTime, setElapsedTime] = useState(0);
|
|
33
|
-
const [operations, setOperations] = useState([]);
|
|
34
|
-
const [isSessionRunning, setIsSessionRunning] = useState(false);
|
|
35
|
-
const [sessionMessage, setSessionMessage] = useState('Processing...');
|
|
36
|
-
const [historyRemountKey, setHistoryRemountKey] = useState(0);
|
|
37
|
-
|
|
38
|
-
const rootUiRef = useRef(null);
|
|
39
|
-
const mainControlsRef = useRef(null);
|
|
40
|
-
|
|
41
|
-
debugLog('UIStateProvider initialized with all state variables');
|
|
42
|
-
|
|
43
|
-
const value = {
|
|
44
|
-
// History
|
|
45
|
-
history,
|
|
46
|
-
setHistory,
|
|
47
|
-
pendingHistoryItems,
|
|
48
|
-
setPendingHistoryItems,
|
|
49
|
-
|
|
50
|
-
// Streaming state
|
|
51
|
-
streamingState,
|
|
52
|
-
setStreamingState,
|
|
53
|
-
currentOperation,
|
|
54
|
-
setCurrentOperation,
|
|
55
|
-
progressMessage,
|
|
56
|
-
setProgressMessage,
|
|
57
|
-
thought,
|
|
58
|
-
setThought,
|
|
59
|
-
|
|
60
|
-
// Operations tracking
|
|
61
|
-
operations,
|
|
62
|
-
setOperations,
|
|
63
|
-
addOperation: (operation) => {
|
|
64
|
-
debugLog(`addOperation: ${operation.type || 'unknown'} - ${operation.name || 'unnamed'}`);
|
|
65
|
-
setOperations(prev => [...prev, {
|
|
66
|
-
...operation,
|
|
67
|
-
id: Date.now(),
|
|
68
|
-
startTime: Date.now(),
|
|
69
|
-
status: 'running'
|
|
70
|
-
}]);
|
|
71
|
-
},
|
|
72
|
-
updateOperation: (id, updates) => {
|
|
73
|
-
debugLog(`updateOperation: id=${id}, updates=${JSON.stringify(updates)}`);
|
|
74
|
-
setOperations(prev => prev.map(op =>
|
|
75
|
-
op.id === id ? { ...op, ...updates } : op
|
|
76
|
-
));
|
|
77
|
-
},
|
|
78
|
-
completeOperation: (id) => {
|
|
79
|
-
debugLog(`completeOperation: id=${id}`);
|
|
80
|
-
setOperations(prev => prev.map(op =>
|
|
81
|
-
op.id === id ? { ...op, status: 'completed', endTime: Date.now() } : op
|
|
82
|
-
));
|
|
83
|
-
},
|
|
84
|
-
|
|
85
|
-
// Layout
|
|
86
|
-
mainAreaWidth,
|
|
87
|
-
setMainAreaWidth,
|
|
88
|
-
terminalHeight,
|
|
89
|
-
setTerminalHeight,
|
|
90
|
-
rootUiRef,
|
|
91
|
-
mainControlsRef,
|
|
92
|
-
|
|
93
|
-
// Timer
|
|
94
|
-
elapsedTime,
|
|
95
|
-
setElapsedTime,
|
|
96
|
-
|
|
97
|
-
// Session state
|
|
98
|
-
isSessionRunning,
|
|
99
|
-
setIsSessionRunning,
|
|
100
|
-
sessionMessage,
|
|
101
|
-
setSessionMessage,
|
|
102
|
-
|
|
103
|
-
// History remount key for Static component optimization
|
|
104
|
-
historyRemountKey,
|
|
105
|
-
setHistoryRemountKey,
|
|
106
|
-
};
|
|
107
|
-
|
|
108
|
-
return React.createElement(UIStateContext.Provider, { value }, children);
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
export function useUIState() {
|
|
112
|
-
const context = useContext(UIStateContext);
|
|
113
|
-
if (!context) {
|
|
114
|
-
throw new Error('useUIState must be used within UIStateProvider');
|
|
115
|
-
}
|
|
116
|
-
return context;
|
|
117
|
-
}
|
package/src/ui/example-usage.js
DELETED
|
@@ -1,180 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Example usage of the UI API
|
|
3
|
-
*
|
|
4
|
-
* This file demonstrates how to use the UI API to update the interface
|
|
5
|
-
* during agentic coding operations.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import {
|
|
9
|
-
StreamingState,
|
|
10
|
-
addHistoryMessage,
|
|
11
|
-
setStreamingState,
|
|
12
|
-
setThought,
|
|
13
|
-
setProgressMessage,
|
|
14
|
-
startOperation,
|
|
15
|
-
updateOperation,
|
|
16
|
-
completeOperation,
|
|
17
|
-
runOperation,
|
|
18
|
-
batchUpdate
|
|
19
|
-
} from './api.js';
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Example: Simple progress update
|
|
23
|
-
*/
|
|
24
|
-
export async function exampleSimpleProgress() {
|
|
25
|
-
// Start responding
|
|
26
|
-
setStreamingState(StreamingState.Responding);
|
|
27
|
-
setThought('Analyzing the code structure...');
|
|
28
|
-
|
|
29
|
-
// Simulate work
|
|
30
|
-
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
31
|
-
|
|
32
|
-
// Update thought
|
|
33
|
-
setThought('Planning the implementation...');
|
|
34
|
-
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
35
|
-
|
|
36
|
-
// Complete
|
|
37
|
-
setStreamingState(StreamingState.Completed);
|
|
38
|
-
addHistoryMessage({
|
|
39
|
-
type: 'assistant',
|
|
40
|
-
text: 'Analysis complete! Here\'s what I found...'
|
|
41
|
-
});
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Example: Multi-step operation with detailed progress
|
|
46
|
-
*/
|
|
47
|
-
export async function exampleDetailedOperations() {
|
|
48
|
-
setStreamingState(StreamingState.Executing);
|
|
49
|
-
|
|
50
|
-
// Operation 1: Reading files
|
|
51
|
-
const readOpId = startOperation({
|
|
52
|
-
type: 'reading',
|
|
53
|
-
name: 'Reading source files',
|
|
54
|
-
description: 'Analyzing codebase structure'
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
58
|
-
|
|
59
|
-
updateOperation(readOpId, {
|
|
60
|
-
progress: 50,
|
|
61
|
-
detail: 'Processing src/components...'
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
65
|
-
|
|
66
|
-
completeOperation(readOpId);
|
|
67
|
-
|
|
68
|
-
// Operation 2: Analyzing
|
|
69
|
-
const analyzeOpId = startOperation({
|
|
70
|
-
type: 'analyzing',
|
|
71
|
-
name: 'Analyzing dependencies',
|
|
72
|
-
description: 'Checking import relationships'
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
await new Promise(resolve => setTimeout(resolve, 1500));
|
|
76
|
-
completeOperation(analyzeOpId);
|
|
77
|
-
|
|
78
|
-
// Operation 3: Writing code
|
|
79
|
-
const writeOpId = startOperation({
|
|
80
|
-
type: 'writing',
|
|
81
|
-
name: 'Writing new component',
|
|
82
|
-
description: 'Creating Button.js'
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
86
|
-
completeOperation(writeOpId);
|
|
87
|
-
|
|
88
|
-
setStreamingState(StreamingState.Completed);
|
|
89
|
-
addHistoryMessage({
|
|
90
|
-
type: 'assistant',
|
|
91
|
-
text: 'Successfully created the new component!'
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Example: Using runOperation helper
|
|
97
|
-
*/
|
|
98
|
-
export async function exampleAutoOperation() {
|
|
99
|
-
setStreamingState(StreamingState.Executing);
|
|
100
|
-
|
|
101
|
-
await runOperation({
|
|
102
|
-
type: 'building',
|
|
103
|
-
name: 'Building project',
|
|
104
|
-
description: 'Running npm run build'
|
|
105
|
-
}, async (update) => {
|
|
106
|
-
// Simulate build steps
|
|
107
|
-
update({ progress: 25, detail: 'Compiling TypeScript...' });
|
|
108
|
-
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
109
|
-
|
|
110
|
-
update({ progress: 50, detail: 'Bundling assets...' });
|
|
111
|
-
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
112
|
-
|
|
113
|
-
update({ progress: 75, detail: 'Optimizing output...' });
|
|
114
|
-
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
115
|
-
|
|
116
|
-
update({ progress: 100, detail: 'Build complete!' });
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
setStreamingState(StreamingState.Completed);
|
|
120
|
-
addHistoryMessage({
|
|
121
|
-
type: 'assistant',
|
|
122
|
-
text: 'Build completed successfully!'
|
|
123
|
-
});
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
/**
|
|
127
|
-
* Example: Batch updates
|
|
128
|
-
*/
|
|
129
|
-
export async function exampleBatchUpdate() {
|
|
130
|
-
batchUpdate({
|
|
131
|
-
streamingState: StreamingState.Responding,
|
|
132
|
-
thought: 'Thinking about the best approach...',
|
|
133
|
-
progressMessage: 'Analyzing requirements',
|
|
134
|
-
addHistory: {
|
|
135
|
-
type: 'system',
|
|
136
|
-
text: 'Starting analysis...'
|
|
137
|
-
}
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
141
|
-
|
|
142
|
-
batchUpdate({
|
|
143
|
-
streamingState: StreamingState.Completed,
|
|
144
|
-
thought: null,
|
|
145
|
-
progressMessage: null,
|
|
146
|
-
addHistory: {
|
|
147
|
-
type: 'assistant',
|
|
148
|
-
text: 'Analysis complete!'
|
|
149
|
-
}
|
|
150
|
-
});
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
/**
|
|
154
|
-
* Example: Error handling
|
|
155
|
-
*/
|
|
156
|
-
export async function exampleErrorHandling() {
|
|
157
|
-
const opId = startOperation({
|
|
158
|
-
type: 'testing',
|
|
159
|
-
name: 'Running tests',
|
|
160
|
-
description: 'npm test'
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
try {
|
|
164
|
-
await new Promise((resolve, reject) => {
|
|
165
|
-
setTimeout(() => reject(new Error('Test failed: timeout')), 1000);
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
completeOperation(opId);
|
|
169
|
-
} catch (error) {
|
|
170
|
-
updateOperation(opId, {
|
|
171
|
-
status: 'error',
|
|
172
|
-
detail: error.message
|
|
173
|
-
});
|
|
174
|
-
|
|
175
|
-
addHistoryMessage({
|
|
176
|
-
type: 'error',
|
|
177
|
-
text: `Test failed: ${error.message}`
|
|
178
|
-
});
|
|
179
|
-
}
|
|
180
|
-
}
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Hook to handle terminal resize events
|
|
3
|
-
* Clears the screen on resize to prevent rendering artifacts
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { useEffect } from 'react';
|
|
7
|
-
import { useStdout } from 'ink';
|
|
8
|
-
|
|
9
|
-
export function useTerminalResize(onResize) {
|
|
10
|
-
const { stdout } = useStdout();
|
|
11
|
-
|
|
12
|
-
useEffect(() => {
|
|
13
|
-
if (!stdout || typeof stdout.on !== 'function') {
|
|
14
|
-
return;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
const handleResize = () => {
|
|
18
|
-
// Clear the screen to prevent artifacts
|
|
19
|
-
if (stdout.write && typeof stdout.write === 'function') {
|
|
20
|
-
// ANSI escape code to clear screen and reset cursor
|
|
21
|
-
stdout.write('\x1Bc');
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
if (onResize) {
|
|
25
|
-
onResize();
|
|
26
|
-
}
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
stdout.on('resize', handleResize);
|
|
30
|
-
|
|
31
|
-
return () => {
|
|
32
|
-
if (stdout.off && typeof stdout.off === 'function') {
|
|
33
|
-
stdout.off('resize', handleResize);
|
|
34
|
-
} else if (stdout.removeListener && typeof stdout.removeListener === 'function') {
|
|
35
|
-
stdout.removeListener('resize', handleResize);
|
|
36
|
-
}
|
|
37
|
-
};
|
|
38
|
-
}, [stdout, onResize]);
|
|
39
|
-
}
|