prompt-language-shell 0.5.2 → 0.6.0
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/config/ANSWER.md +4 -0
- package/dist/config/PLAN.md +23 -0
- package/dist/config/VALIDATE.md +12 -11
- package/dist/services/components.js +54 -64
- package/dist/services/configuration.js +84 -0
- package/dist/services/messages.js +22 -0
- package/dist/services/queue.js +2 -2
- package/dist/services/refinement.js +36 -0
- package/dist/services/task-router.js +135 -0
- package/dist/types/types.js +0 -1
- package/dist/ui/Answer.js +18 -27
- package/dist/ui/Command.js +45 -27
- package/dist/ui/Component.js +23 -50
- package/dist/ui/Config.js +49 -24
- package/dist/ui/Confirm.js +17 -11
- package/dist/ui/Execute.js +66 -45
- package/dist/ui/Feedback.js +1 -1
- package/dist/ui/Introspect.js +26 -23
- package/dist/ui/Main.js +71 -100
- package/dist/ui/Message.js +1 -1
- package/dist/ui/Plan.js +54 -32
- package/dist/ui/Refinement.js +6 -7
- package/dist/ui/Report.js +1 -1
- package/dist/ui/UserQuery.js +6 -0
- package/dist/ui/Validate.js +49 -19
- package/dist/ui/Welcome.js +1 -1
- package/dist/ui/Workflow.js +119 -0
- package/package.json +1 -1
- package/dist/handlers/answer.js +0 -21
- package/dist/handlers/command.js +0 -34
- package/dist/handlers/config.js +0 -88
- package/dist/handlers/execute.js +0 -46
- package/dist/handlers/execution.js +0 -140
- package/dist/handlers/introspect.js +0 -21
- package/dist/handlers/plan.js +0 -79
- package/dist/types/handlers.js +0 -1
- package/dist/ui/AnswerDisplay.js +0 -8
- package/dist/ui/Column.js +0 -7
package/dist/ui/Confirm.js
CHANGED
|
@@ -1,26 +1,32 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import
|
|
2
|
+
import { useState } from 'react';
|
|
3
3
|
import { Box, Text } from 'ink';
|
|
4
4
|
import { Colors, Palette } from '../services/colors.js';
|
|
5
5
|
import { useInput } from '../services/keyboard.js';
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const [selectedIndex, setSelectedIndex] =
|
|
6
|
+
import { UserQuery } from './UserQuery.js';
|
|
7
|
+
export function Confirm({ message, state, isActive = true, handlers, onConfirmed, onCancelled, }) {
|
|
8
|
+
// isActive passed as prop
|
|
9
|
+
const [selectedIndex, setSelectedIndex] = useState(state?.selectedIndex ?? 0); // 0 = Yes, 1 = No
|
|
10
10
|
useInput((input, key) => {
|
|
11
|
-
if (
|
|
11
|
+
if (!isActive)
|
|
12
12
|
return;
|
|
13
13
|
if (key.escape) {
|
|
14
14
|
// Escape: highlight "No" and cancel
|
|
15
15
|
setSelectedIndex(1);
|
|
16
|
+
handlers?.updateState({ selectedIndex: 1 });
|
|
16
17
|
onCancelled?.();
|
|
17
18
|
}
|
|
18
19
|
else if (key.tab) {
|
|
19
20
|
// Toggle between Yes (0) and No (1)
|
|
20
|
-
setSelectedIndex((prev) =>
|
|
21
|
+
setSelectedIndex((prev) => {
|
|
22
|
+
const newIndex = prev === 0 ? 1 : 0;
|
|
23
|
+
handlers?.updateState({ selectedIndex: newIndex });
|
|
24
|
+
return newIndex;
|
|
25
|
+
});
|
|
21
26
|
}
|
|
22
27
|
else if (key.return) {
|
|
23
28
|
// Confirm selection
|
|
29
|
+
handlers?.updateState({ selectedIndex, confirmed: true });
|
|
24
30
|
if (selectedIndex === 0) {
|
|
25
31
|
onConfirmed?.();
|
|
26
32
|
}
|
|
@@ -28,16 +34,16 @@ export function Confirm({ message, state, onConfirmed, onCancelled, }) {
|
|
|
28
34
|
onCancelled?.();
|
|
29
35
|
}
|
|
30
36
|
}
|
|
31
|
-
}, { isActive
|
|
37
|
+
}, { isActive });
|
|
32
38
|
const options = [
|
|
33
39
|
{ label: 'yes', value: 'yes', color: Palette.BrightGreen },
|
|
34
40
|
{ label: 'no', value: 'no', color: Colors.Status.Error },
|
|
35
41
|
];
|
|
36
|
-
if (
|
|
42
|
+
if (!isActive) {
|
|
37
43
|
// When done, show both the message and user's choice in timeline
|
|
38
|
-
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { color: undefined, children: message }) }),
|
|
44
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { marginBottom: 1, marginLeft: 1, children: _jsx(Text, { color: undefined, children: message }) }), _jsxs(UserQuery, { children: ["> ", options[selectedIndex].label] })] }));
|
|
39
45
|
}
|
|
40
|
-
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { color:
|
|
46
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { marginBottom: 1, marginLeft: 1, children: _jsx(Text, { color: isActive ? Colors.Text.Active : Colors.Text.Inactive, children: message }) }), _jsxs(Box, { marginLeft: 1, children: [_jsx(Text, { color: Colors.Action.Select, children: ">" }), _jsx(Text, { children: " " }), _jsx(Box, { children: options.map((option, index) => {
|
|
41
47
|
const isSelected = index === selectedIndex;
|
|
42
48
|
return (_jsx(Box, { marginRight: 2, children: _jsx(Text, { color: isSelected ? option.color : undefined, dimColor: !isSelected, children: option.label }) }, option.value));
|
|
43
49
|
}) })] })] }));
|
package/dist/ui/Execute.js
CHANGED
|
@@ -85,41 +85,53 @@ function CommandStatusDisplay({ item, elapsed }) {
|
|
|
85
85
|
const elapsedTime = getElapsedTime();
|
|
86
86
|
return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { paddingLeft: 2, children: [_jsx(Text, { color: colors.icon, children: STATUS_ICONS[item.status] }), _jsx(Text, { color: colors.description, children: item.label || item.command.description }), elapsedTime !== undefined && (_jsxs(Text, { color: Palette.DarkGray, children: [" (", formatDuration(elapsedTime), ")"] }))] }), _jsxs(Box, { paddingLeft: 5, children: [_jsx(Text, { color: colors.symbol, children: "\u221F " }), _jsx(Text, { color: colors.command, children: item.command.command }), item.status === ExecutionStatus.Running && (_jsxs(Text, { children: [' ', _jsx(Spinner, {})] }))] })] }));
|
|
87
87
|
}
|
|
88
|
-
export function Execute({ tasks, state,
|
|
89
|
-
|
|
90
|
-
const
|
|
91
|
-
const [error, setError] = useState(null);
|
|
92
|
-
const [isLoading, setIsLoading] = useState(state?.isLoading ?? !done);
|
|
88
|
+
export function Execute({ tasks, state, isActive = true, service, handlers, }) {
|
|
89
|
+
// isActive passed as prop
|
|
90
|
+
const [error, setError] = useState(state?.error ?? null);
|
|
93
91
|
const [isExecuting, setIsExecuting] = useState(false);
|
|
94
|
-
const [commandStatuses, setCommandStatuses] = useState([]);
|
|
95
|
-
const [message, setMessage] = useState('');
|
|
92
|
+
const [commandStatuses, setCommandStatuses] = useState(state?.commandStatuses ?? []);
|
|
93
|
+
const [message, setMessage] = useState(state?.message ?? '');
|
|
96
94
|
const [currentElapsed, setCurrentElapsed] = useState(0);
|
|
97
95
|
const [runningIndex, setRunningIndex] = useState(null);
|
|
98
96
|
const [outputs, setOutputs] = useState([]);
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
97
|
+
const [hasProcessed, setHasProcessed] = useState(false);
|
|
98
|
+
// Derive loading state from current conditions
|
|
99
|
+
const isLoading = isActive &&
|
|
100
|
+
commandStatuses.length === 0 &&
|
|
101
|
+
!error &&
|
|
102
|
+
!isExecuting &&
|
|
103
|
+
!hasProcessed;
|
|
104
|
+
useInput((_, key) => {
|
|
105
|
+
if (key.escape && (isLoading || isExecuting) && isActive) {
|
|
102
106
|
setIsExecuting(false);
|
|
103
107
|
setRunningIndex(null);
|
|
104
108
|
// Mark any running command as aborted when cancelled
|
|
105
109
|
const now = Date.now();
|
|
106
|
-
setCommandStatuses((prev) =>
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
110
|
+
setCommandStatuses((prev) => {
|
|
111
|
+
const updated = prev.map((item) => {
|
|
112
|
+
if (item.status === ExecutionStatus.Running) {
|
|
113
|
+
const elapsed = item.startTime
|
|
114
|
+
? Math.floor((now - item.startTime) / 1000) * 1000
|
|
115
|
+
: undefined;
|
|
116
|
+
return {
|
|
117
|
+
...item,
|
|
118
|
+
status: ExecutionStatus.Aborted,
|
|
119
|
+
endTime: now,
|
|
120
|
+
elapsed,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
return item;
|
|
124
|
+
});
|
|
125
|
+
// Save state after updating
|
|
126
|
+
handlers?.updateState({
|
|
127
|
+
commandStatuses: updated,
|
|
128
|
+
message,
|
|
129
|
+
});
|
|
130
|
+
return updated;
|
|
131
|
+
});
|
|
132
|
+
handlers?.onAborted('execution');
|
|
121
133
|
}
|
|
122
|
-
}, { isActive: (isLoading || isExecuting) &&
|
|
134
|
+
}, { isActive: (isLoading || isExecuting) && isActive });
|
|
123
135
|
// Update elapsed time for running command
|
|
124
136
|
useEffect(() => {
|
|
125
137
|
if (runningIndex === null)
|
|
@@ -139,15 +151,20 @@ export function Execute({ tasks, state, service, onError, onComplete, onAborted,
|
|
|
139
151
|
useEffect(() => {
|
|
140
152
|
if (isExecuting || commandStatuses.length === 0 || !outputs.length)
|
|
141
153
|
return;
|
|
142
|
-
|
|
143
|
-
|
|
154
|
+
// Save state before completing
|
|
155
|
+
handlers?.updateState({
|
|
156
|
+
message,
|
|
157
|
+
commandStatuses,
|
|
158
|
+
error,
|
|
159
|
+
});
|
|
160
|
+
handlers?.onComplete();
|
|
161
|
+
}, [isExecuting, commandStatuses, outputs, handlers, message, error]);
|
|
144
162
|
useEffect(() => {
|
|
145
|
-
if (
|
|
163
|
+
if (!isActive) {
|
|
146
164
|
return;
|
|
147
165
|
}
|
|
148
166
|
if (!service) {
|
|
149
167
|
setError('No service available');
|
|
150
|
-
setIsLoading(false);
|
|
151
168
|
return;
|
|
152
169
|
}
|
|
153
170
|
let mounted = true;
|
|
@@ -173,9 +190,14 @@ export function Execute({ tasks, state, service, onError, onComplete, onAborted,
|
|
|
173
190
|
if (!mounted)
|
|
174
191
|
return;
|
|
175
192
|
if (!result.commands || result.commands.length === 0) {
|
|
176
|
-
setIsLoading(false);
|
|
177
193
|
setOutputs([]);
|
|
178
|
-
|
|
194
|
+
setHasProcessed(true);
|
|
195
|
+
// Save state before completing
|
|
196
|
+
handlers?.updateState({
|
|
197
|
+
message: result.message,
|
|
198
|
+
commandStatuses: [],
|
|
199
|
+
});
|
|
200
|
+
handlers?.onComplete();
|
|
179
201
|
return;
|
|
180
202
|
}
|
|
181
203
|
// Resolve placeholders in command strings before execution
|
|
@@ -190,7 +212,6 @@ export function Execute({ tasks, state, service, onError, onComplete, onAborted,
|
|
|
190
212
|
status: ExecutionStatus.Pending,
|
|
191
213
|
label: tasks[index]?.action,
|
|
192
214
|
})));
|
|
193
|
-
setIsLoading(false);
|
|
194
215
|
setIsExecuting(true);
|
|
195
216
|
// Execute commands sequentially
|
|
196
217
|
const outputs = await executeCommands(resolvedCommands, (progress) => {
|
|
@@ -236,14 +257,14 @@ export function Execute({ tasks, state, service, onError, onComplete, onAborted,
|
|
|
236
257
|
await ensureMinimumTime(startTime, MINIMUM_PROCESSING_TIME);
|
|
237
258
|
if (mounted) {
|
|
238
259
|
const errorMessage = formatErrorMessage(err);
|
|
239
|
-
setIsLoading(false);
|
|
240
260
|
setIsExecuting(false);
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
}
|
|
261
|
+
setError(errorMessage);
|
|
262
|
+
setHasProcessed(true);
|
|
263
|
+
// Save error state
|
|
264
|
+
handlers?.updateState({
|
|
265
|
+
error: errorMessage,
|
|
266
|
+
});
|
|
267
|
+
handlers?.onError(errorMessage);
|
|
247
268
|
}
|
|
248
269
|
}
|
|
249
270
|
}
|
|
@@ -251,12 +272,12 @@ export function Execute({ tasks, state, service, onError, onComplete, onAborted,
|
|
|
251
272
|
return () => {
|
|
252
273
|
mounted = false;
|
|
253
274
|
};
|
|
254
|
-
}, [tasks,
|
|
275
|
+
}, [tasks, isActive, service, handlers]);
|
|
255
276
|
// Return null only when loading completes with no commands
|
|
256
|
-
if (
|
|
277
|
+
if (!isActive && commandStatuses.length === 0 && !error) {
|
|
257
278
|
return null;
|
|
258
279
|
}
|
|
259
|
-
// Show completed steps when
|
|
260
|
-
const showCompletedSteps =
|
|
261
|
-
return (_jsxs(Box, { alignSelf: "flex-start", flexDirection: "column", children: [isLoading && (_jsxs(Box, { children: [_jsx(Text, { color: getTextColor(
|
|
280
|
+
// Show completed steps when not active
|
|
281
|
+
const showCompletedSteps = !isActive && commandStatuses.length > 0;
|
|
282
|
+
return (_jsxs(Box, { alignSelf: "flex-start", flexDirection: "column", children: [isLoading && (_jsxs(Box, { marginLeft: 1, children: [_jsx(Text, { color: getTextColor(isActive), children: "Preparing commands. " }), _jsx(Spinner, {})] })), (isExecuting || showCompletedSteps) && (_jsxs(Box, { flexDirection: "column", marginLeft: 1, children: [message && (_jsxs(Box, { marginBottom: 1, children: [_jsx(Text, { color: getTextColor(isActive), children: message }), isExecuting && (_jsxs(Text, { children: [' ', _jsx(Spinner, {})] }))] })), commandStatuses.map((item, index) => (_jsx(Box, { marginBottom: index < commandStatuses.length - 1 ? 1 : 0, children: _jsx(CommandStatusDisplay, { item: item, elapsed: index === runningIndex ? currentElapsed : undefined }) }, index)))] })), error && (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: Colors.Status.Error, children: ["Error: ", error] }) }))] }));
|
|
262
283
|
}
|
package/dist/ui/Feedback.js
CHANGED
|
@@ -13,5 +13,5 @@ function getSymbol(type) {
|
|
|
13
13
|
export function Feedback({ type, message }) {
|
|
14
14
|
const color = getFeedbackColor(type, false);
|
|
15
15
|
const symbol = getSymbol(type);
|
|
16
|
-
return (_jsx(Box, { children: _jsxs(Text, { color: color, children: [symbol, " ", message] }) }));
|
|
16
|
+
return (_jsx(Box, { marginLeft: 1, children: _jsxs(Text, { color: color, children: [symbol, " ", message] }) }));
|
|
17
17
|
}
|
package/dist/ui/Introspect.js
CHANGED
|
@@ -2,6 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { useEffect, useState } from 'react';
|
|
3
3
|
import { Box, Text } from 'ink';
|
|
4
4
|
import { Colors, getTextColor } from '../services/colors.js';
|
|
5
|
+
import { createReportDefinition } from '../services/components.js';
|
|
5
6
|
import { useInput } from '../services/keyboard.js';
|
|
6
7
|
import { formatErrorMessage } from '../services/messages.js';
|
|
7
8
|
import { ensureMinimumTime } from '../services/timing.js';
|
|
@@ -41,26 +42,22 @@ function parseCapabilityFromTask(task) {
|
|
|
41
42
|
isIndirect,
|
|
42
43
|
};
|
|
43
44
|
}
|
|
44
|
-
export function Introspect({ tasks, state, service, children, debug = false,
|
|
45
|
-
|
|
46
|
-
const isCurrent = done === false;
|
|
45
|
+
export function Introspect({ tasks, state, isActive = true, service, children, debug = false, handlers, }) {
|
|
46
|
+
// isActive passed as prop
|
|
47
47
|
const [error, setError] = useState(null);
|
|
48
|
-
const [isLoading, setIsLoading] = useState(state?.isLoading ?? !done);
|
|
49
48
|
useInput((input, key) => {
|
|
50
|
-
if (key.escape &&
|
|
51
|
-
|
|
52
|
-
onAborted();
|
|
49
|
+
if (key.escape && isActive) {
|
|
50
|
+
handlers?.onAborted('introspection');
|
|
53
51
|
}
|
|
54
|
-
}, { isActive
|
|
52
|
+
}, { isActive });
|
|
55
53
|
useEffect(() => {
|
|
56
|
-
// Skip processing if
|
|
57
|
-
if (
|
|
54
|
+
// Skip processing if not active
|
|
55
|
+
if (!isActive) {
|
|
58
56
|
return;
|
|
59
57
|
}
|
|
60
58
|
// Skip processing if no service available
|
|
61
59
|
if (!service) {
|
|
62
60
|
setError('No service available');
|
|
63
|
-
setIsLoading(false);
|
|
64
61
|
return;
|
|
65
62
|
}
|
|
66
63
|
let mounted = true;
|
|
@@ -81,21 +78,27 @@ export function Introspect({ tasks, state, service, children, debug = false, onE
|
|
|
81
78
|
cap.name.toUpperCase() !== 'VALIDATE' &&
|
|
82
79
|
cap.name.toUpperCase() !== 'REPORT');
|
|
83
80
|
}
|
|
84
|
-
|
|
85
|
-
|
|
81
|
+
// Save state before completing
|
|
82
|
+
handlers?.updateState({
|
|
83
|
+
capabilities,
|
|
84
|
+
message: result.message,
|
|
85
|
+
});
|
|
86
|
+
// Add Report component to queue
|
|
87
|
+
handlers?.addToQueue(createReportDefinition(result.message, capabilities));
|
|
88
|
+
// Signal completion
|
|
89
|
+
handlers?.onComplete();
|
|
86
90
|
}
|
|
87
91
|
}
|
|
88
92
|
catch (err) {
|
|
89
93
|
await ensureMinimumTime(startTime, MIN_PROCESSING_TIME);
|
|
90
94
|
if (mounted) {
|
|
91
95
|
const errorMessage = formatErrorMessage(err);
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
}
|
|
96
|
+
setError(errorMessage);
|
|
97
|
+
// Save error state
|
|
98
|
+
handlers?.updateState({
|
|
99
|
+
error: errorMessage,
|
|
100
|
+
});
|
|
101
|
+
handlers?.onError(errorMessage);
|
|
99
102
|
}
|
|
100
103
|
}
|
|
101
104
|
}
|
|
@@ -103,10 +106,10 @@ export function Introspect({ tasks, state, service, children, debug = false, onE
|
|
|
103
106
|
return () => {
|
|
104
107
|
mounted = false;
|
|
105
108
|
};
|
|
106
|
-
}, [tasks,
|
|
109
|
+
}, [tasks, isActive, service, debug, handlers]);
|
|
107
110
|
// Don't render wrapper when done and nothing to show
|
|
108
|
-
if (!
|
|
111
|
+
if (!isActive && !error && !children) {
|
|
109
112
|
return null;
|
|
110
113
|
}
|
|
111
|
-
return (_jsxs(Box, { alignSelf: "flex-start", flexDirection: "column", children: [
|
|
114
|
+
return (_jsxs(Box, { alignSelf: "flex-start", flexDirection: "column", children: [isActive && (_jsxs(Box, { marginLeft: 1, children: [_jsx(Text, { color: getTextColor(isActive), children: "Listing capabilities. " }), _jsx(Spinner, {})] })), error && (_jsx(Box, { marginTop: 1, marginLeft: 1, children: _jsxs(Text, { color: Colors.Status.Error, children: ["Error: ", error] }) })), children] }));
|
|
112
115
|
}
|
package/dist/ui/Main.js
CHANGED
|
@@ -1,33 +1,17 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import
|
|
2
|
+
import { useEffect, useState } from 'react';
|
|
3
3
|
import { FeedbackType } from '../types/types.js';
|
|
4
4
|
import { createAnthropicService, } from '../services/anthropic.js';
|
|
5
|
-
import { createCommandDefinition,
|
|
6
|
-
import { getConfigurationRequiredMessage,
|
|
5
|
+
import { createCommandDefinition, createConfigDefinitionWithKeys, createFeedback, createMessage, createWelcomeDefinition, } from '../services/components.js';
|
|
6
|
+
import { getConfigurationRequiredMessage, getMissingConfigKeys, loadConfig, loadDebugSetting, saveAnthropicConfig, saveDebugSetting, } from '../services/configuration.js';
|
|
7
7
|
import { registerGlobalShortcut } from '../services/keyboard.js';
|
|
8
|
-
import {
|
|
9
|
-
import { exitApp } from '../services/process.js';
|
|
10
|
-
import { createAnswerHandlers } from '../handlers/answer.js';
|
|
11
|
-
import { createCommandHandlers } from '../handlers/command.js';
|
|
12
|
-
import { createConfigHandlers } from '../handlers/config.js';
|
|
13
|
-
import { createExecuteHandlers } from '../handlers/execute.js';
|
|
14
|
-
import { createExecutionHandlers } from '../handlers/execution.js';
|
|
15
|
-
import { createIntrospectHandlers } from '../handlers/introspect.js';
|
|
16
|
-
import { createPlanHandlers } from '../handlers/plan.js';
|
|
17
|
-
import { Column } from './Column.js';
|
|
8
|
+
import { Workflow } from './Workflow.js';
|
|
18
9
|
export const Main = ({ app, command }) => {
|
|
19
|
-
const [service, setService] =
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
return createAnthropicService(config.anthropic);
|
|
23
|
-
}
|
|
24
|
-
return null;
|
|
25
|
-
});
|
|
26
|
-
const [timeline, setTimeline] = React.useState([]);
|
|
27
|
-
const [queue, setQueue] = React.useState([]);
|
|
28
|
-
const [isDebug, setIsDebug] = React.useState(() => loadDebugSetting());
|
|
10
|
+
const [service, setService] = useState(null);
|
|
11
|
+
const [initialQueue, setInitialQueue] = useState(null);
|
|
12
|
+
const [isDebug, setIsDebug] = useState(() => loadDebugSetting());
|
|
29
13
|
// Register global keyboard shortcuts
|
|
30
|
-
|
|
14
|
+
useEffect(() => {
|
|
31
15
|
registerGlobalShortcut('shift+tab', () => {
|
|
32
16
|
setIsDebug((prev) => {
|
|
33
17
|
const newValue = !prev;
|
|
@@ -36,88 +20,75 @@ export const Main = ({ app, command }) => {
|
|
|
36
20
|
});
|
|
37
21
|
});
|
|
38
22
|
}, []);
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
23
|
+
// Initialize service on mount
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
if (service !== null) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
const missingKeys = getMissingConfigKeys();
|
|
29
|
+
if (missingKeys.length === 0) {
|
|
30
|
+
// Config exists - create service immediately
|
|
31
|
+
try {
|
|
32
|
+
const config = loadConfig();
|
|
33
|
+
const newService = createAnthropicService(config.anthropic);
|
|
34
|
+
setService(newService);
|
|
50
35
|
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
if (currentQueue.length === 0)
|
|
58
|
-
return currentQueue;
|
|
59
|
-
const [first] = currentQueue;
|
|
60
|
-
if (!isStateless(first)) {
|
|
61
|
-
addToTimeline(markAsDone(first), createFeedback(FeedbackType.Aborted, getCancellationMessage(operationName)));
|
|
36
|
+
catch (error) {
|
|
37
|
+
// Service creation failed - show error and exit
|
|
38
|
+
const errorMessage = error instanceof Error
|
|
39
|
+
? error.message
|
|
40
|
+
: 'Failed to initialize service';
|
|
41
|
+
setInitialQueue([createFeedback(FeedbackType.Failed, errorMessage)]);
|
|
62
42
|
}
|
|
63
|
-
exitApp(0);
|
|
64
|
-
return [];
|
|
65
|
-
});
|
|
66
|
-
}, [addToTimeline]);
|
|
67
|
-
// Create operations object
|
|
68
|
-
const ops = React.useMemo(() => ({
|
|
69
|
-
addToTimeline,
|
|
70
|
-
setQueue,
|
|
71
|
-
service,
|
|
72
|
-
}), [addToTimeline, service]);
|
|
73
|
-
// Create handlers in dependency order
|
|
74
|
-
const introspectHandlers = React.useMemo(() => createIntrospectHandlers(ops, handleAborted), [ops, handleAborted]);
|
|
75
|
-
const answerHandlers = React.useMemo(() => createAnswerHandlers(ops, handleAborted), [ops, handleAborted]);
|
|
76
|
-
const executeHandlers = React.useMemo(() => createExecuteHandlers(ops, handleAborted), [ops, handleAborted]);
|
|
77
|
-
const executionHandlers = React.useMemo(() => createExecutionHandlers(ops, {
|
|
78
|
-
introspect: introspectHandlers,
|
|
79
|
-
answer: answerHandlers,
|
|
80
|
-
execute: executeHandlers,
|
|
81
|
-
}), [ops, introspectHandlers, answerHandlers, executeHandlers]);
|
|
82
|
-
const planHandlers = React.useMemo(() => createPlanHandlers(ops, handleAborted, executionHandlers), [ops, handleAborted, executionHandlers]);
|
|
83
|
-
const commandHandlers = React.useMemo(() => createCommandHandlers(ops, handleAborted, planHandlers, executionHandlers), [ops, handleAborted, planHandlers, executionHandlers]);
|
|
84
|
-
const configHandlers = React.useMemo(() => createConfigHandlers(ops, handleAborted, command, commandHandlers, setService), [ops, handleAborted, command, commandHandlers]);
|
|
85
|
-
// Initialize queue on mount
|
|
86
|
-
React.useEffect(() => {
|
|
87
|
-
const hasConfig = !!service;
|
|
88
|
-
if (command && hasConfig) {
|
|
89
|
-
setQueue([
|
|
90
|
-
createCommandDefinition(command, service, commandHandlers.onError, commandHandlers.onComplete, commandHandlers.onAborted),
|
|
91
|
-
]);
|
|
92
43
|
}
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
44
|
+
// If config is missing, service will be created after config completes
|
|
45
|
+
}, [service]);
|
|
46
|
+
// Initialize queue after service is ready
|
|
47
|
+
useEffect(() => {
|
|
48
|
+
// Only set initial queue once
|
|
49
|
+
if (initialQueue !== null) {
|
|
50
|
+
return;
|
|
98
51
|
}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
52
|
+
const missingKeys = getMissingConfigKeys();
|
|
53
|
+
if (missingKeys.length > 0) {
|
|
54
|
+
// Missing config - show initial configuration flow
|
|
55
|
+
const handleConfigFinished = (config) => {
|
|
56
|
+
// Save config and create service
|
|
57
|
+
try {
|
|
58
|
+
const newConfig = saveAnthropicConfig(config);
|
|
59
|
+
const newService = createAnthropicService(newConfig.anthropic);
|
|
60
|
+
setService(newService);
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
// Config creation failed - show error
|
|
64
|
+
const errorMessage = error instanceof Error
|
|
65
|
+
? error.message
|
|
66
|
+
: 'Failed to save configuration';
|
|
67
|
+
setInitialQueue([createFeedback(FeedbackType.Failed, errorMessage)]);
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
const handleConfigAborted = (operation) => {
|
|
71
|
+
// Config was cancelled - just exit
|
|
72
|
+
};
|
|
73
|
+
setInitialQueue([
|
|
104
74
|
createWelcomeDefinition(app),
|
|
105
|
-
createMessage(getConfigurationRequiredMessage(
|
|
106
|
-
|
|
75
|
+
createMessage(getConfigurationRequiredMessage()),
|
|
76
|
+
createConfigDefinitionWithKeys(missingKeys, handleConfigFinished, handleConfigAborted),
|
|
107
77
|
]);
|
|
108
78
|
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
if (queue.length === 0 && timeline.length > 0) {
|
|
117
|
-
exitApp(0);
|
|
79
|
+
else if (service && command) {
|
|
80
|
+
// Valid service exists and command provided - execute command
|
|
81
|
+
setInitialQueue([createCommandDefinition(command, service)]);
|
|
82
|
+
}
|
|
83
|
+
else if (service && !command) {
|
|
84
|
+
// Valid service exists, no command - show welcome
|
|
85
|
+
setInitialQueue([createWelcomeDefinition(app)]);
|
|
118
86
|
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
87
|
+
// Wait for service to be initialized before setting queue
|
|
88
|
+
}, [app, command, service, initialQueue]);
|
|
89
|
+
// Don't render until initial queue is ready
|
|
90
|
+
if (initialQueue === null) {
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
return _jsx(Workflow, { initialQueue: initialQueue, debug: isDebug });
|
|
123
94
|
};
|
package/dist/ui/Message.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { Box, Text } from 'ink';
|
|
3
3
|
export const Message = ({ text }) => {
|
|
4
|
-
return (_jsx(Box, { children: _jsx(Text, { children: text }) }));
|
|
4
|
+
return (_jsx(Box, { marginLeft: 1, children: _jsx(Text, { children: text }) }));
|
|
5
5
|
};
|