prompt-language-shell 0.5.0 → 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/README.md +114 -10
- package/dist/config/ANSWER.md +4 -0
- package/dist/config/INTROSPECT.md +4 -3
- 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 +27 -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 +12 -5
- 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/Config.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
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, useFocus } from 'ink';
|
|
4
4
|
import TextInput from 'ink-text-input';
|
|
5
5
|
import { Colors } from '../services/colors.js';
|
|
@@ -10,8 +10,8 @@ export var StepType;
|
|
|
10
10
|
StepType["Selection"] = "selection";
|
|
11
11
|
})(StepType || (StepType = {}));
|
|
12
12
|
function TextStep({ value, placeholder, validate, onChange, onSubmit, }) {
|
|
13
|
-
const [inputValue, setInputValue] =
|
|
14
|
-
const [validationFailed, setValidationFailed] =
|
|
13
|
+
const [inputValue, setInputValue] = useState(value);
|
|
14
|
+
const [validationFailed, setValidationFailed] = useState(false);
|
|
15
15
|
const { isFocused } = useFocus({ autoFocus: true });
|
|
16
16
|
const handleChange = (newValue) => {
|
|
17
17
|
setInputValue(newValue);
|
|
@@ -57,20 +57,27 @@ function SelectionStep({ options, selectedIndex, isCurrentStep, }) {
|
|
|
57
57
|
return (_jsx(Box, { marginRight: 2, children: _jsx(Text, { dimColor: !isSelected || !isCurrentStep, bold: isSelected, children: option.label }) }, option.value));
|
|
58
58
|
}) }));
|
|
59
59
|
}
|
|
60
|
-
export function Config({ steps, state, debug, onFinished, onAborted }) {
|
|
61
|
-
|
|
62
|
-
const [step, setStep] =
|
|
63
|
-
const [values, setValues] =
|
|
60
|
+
export function Config({ steps, state, isActive = true, debug, handlers, onFinished, onAborted, }) {
|
|
61
|
+
// isActive passed as prop
|
|
62
|
+
const [step, setStep] = useState(!isActive ? (state?.completedStep ?? steps.length) : 0);
|
|
63
|
+
const [values, setValues] = useState(() => {
|
|
64
|
+
// If not active and we have saved state values, use those
|
|
65
|
+
if (!isActive && state?.values) {
|
|
66
|
+
return state.values;
|
|
67
|
+
}
|
|
68
|
+
// Otherwise initialize from step defaults
|
|
64
69
|
const initial = {};
|
|
65
70
|
steps.forEach((stepConfig) => {
|
|
71
|
+
// Use full path if available, otherwise use key
|
|
72
|
+
const configKey = stepConfig.path || stepConfig.key;
|
|
66
73
|
switch (stepConfig.type) {
|
|
67
74
|
case StepType.Text:
|
|
68
75
|
if (stepConfig.value !== null) {
|
|
69
|
-
initial[
|
|
76
|
+
initial[configKey] = stepConfig.value;
|
|
70
77
|
}
|
|
71
78
|
break;
|
|
72
79
|
case StepType.Selection:
|
|
73
|
-
initial[
|
|
80
|
+
initial[configKey] =
|
|
74
81
|
stepConfig.options[stepConfig.defaultIndex].value;
|
|
75
82
|
break;
|
|
76
83
|
default: {
|
|
@@ -81,8 +88,8 @@ export function Config({ steps, state, debug, onFinished, onAborted }) {
|
|
|
81
88
|
});
|
|
82
89
|
return initial;
|
|
83
90
|
});
|
|
84
|
-
const [inputValue, setInputValue] =
|
|
85
|
-
const [selectedIndex, setSelectedIndex] =
|
|
91
|
+
const [inputValue, setInputValue] = useState('');
|
|
92
|
+
const [selectedIndex, setSelectedIndex] = useState(() => {
|
|
86
93
|
const firstStep = steps[0];
|
|
87
94
|
return firstStep?.type === StepType.Selection ? firstStep.defaultIndex : 0;
|
|
88
95
|
});
|
|
@@ -93,19 +100,20 @@ export function Config({ steps, state, debug, onFinished, onAborted }) {
|
|
|
93
100
|
return value.replace(/\n/g, '').trim();
|
|
94
101
|
};
|
|
95
102
|
useInput((input, key) => {
|
|
96
|
-
if (key.escape &&
|
|
103
|
+
if (key.escape && isActive && step < steps.length) {
|
|
97
104
|
// Save current value before aborting
|
|
98
105
|
const currentStepConfig = steps[step];
|
|
99
106
|
if (currentStepConfig) {
|
|
107
|
+
const configKey = currentStepConfig.path || currentStepConfig.key;
|
|
100
108
|
let currentValue = '';
|
|
101
109
|
switch (currentStepConfig.type) {
|
|
102
110
|
case StepType.Text:
|
|
103
|
-
currentValue = inputValue || values[
|
|
111
|
+
currentValue = inputValue || values[configKey] || '';
|
|
104
112
|
break;
|
|
105
113
|
case StepType.Selection:
|
|
106
114
|
currentValue =
|
|
107
115
|
currentStepConfig.options[selectedIndex]?.value ||
|
|
108
|
-
values[
|
|
116
|
+
values[configKey] ||
|
|
109
117
|
'';
|
|
110
118
|
break;
|
|
111
119
|
default: {
|
|
@@ -114,16 +122,16 @@ export function Config({ steps, state, debug, onFinished, onAborted }) {
|
|
|
114
122
|
}
|
|
115
123
|
}
|
|
116
124
|
if (currentValue) {
|
|
117
|
-
setValues({ ...values, [
|
|
125
|
+
setValues({ ...values, [configKey]: currentValue });
|
|
118
126
|
}
|
|
119
127
|
}
|
|
120
128
|
if (onAborted) {
|
|
121
|
-
onAborted();
|
|
129
|
+
onAborted('configuration');
|
|
122
130
|
}
|
|
123
131
|
return;
|
|
124
132
|
}
|
|
125
133
|
const currentStep = steps[step];
|
|
126
|
-
if (
|
|
134
|
+
if (isActive && step < steps.length && currentStep) {
|
|
127
135
|
switch (currentStep.type) {
|
|
128
136
|
case StepType.Selection:
|
|
129
137
|
if (key.tab) {
|
|
@@ -173,7 +181,9 @@ export function Config({ steps, state, debug, onFinished, onAborted }) {
|
|
|
173
181
|
if (!finalValue) {
|
|
174
182
|
return;
|
|
175
183
|
}
|
|
176
|
-
|
|
184
|
+
// Use full path if available, otherwise use key
|
|
185
|
+
const configKey = currentStepConfig.path || currentStepConfig.key;
|
|
186
|
+
const newValues = { ...values, [configKey]: finalValue };
|
|
177
187
|
setValues(newValues);
|
|
178
188
|
setInputValue('');
|
|
179
189
|
if (step === steps.length - 1) {
|
|
@@ -181,9 +191,21 @@ export function Config({ steps, state, debug, onFinished, onAborted }) {
|
|
|
181
191
|
if (onFinished) {
|
|
182
192
|
onFinished(newValues);
|
|
183
193
|
}
|
|
194
|
+
// Save state before completing
|
|
195
|
+
handlers?.updateState({
|
|
196
|
+
values: newValues,
|
|
197
|
+
completedStep: steps.length,
|
|
198
|
+
});
|
|
199
|
+
// Signal Workflow that config is complete
|
|
200
|
+
handlers?.onComplete();
|
|
184
201
|
setStep(steps.length);
|
|
185
202
|
}
|
|
186
203
|
else {
|
|
204
|
+
// Save state after each step
|
|
205
|
+
handlers?.updateState({
|
|
206
|
+
values: newValues,
|
|
207
|
+
completedStep: step + 1,
|
|
208
|
+
});
|
|
187
209
|
setStep(step + 1);
|
|
188
210
|
// Reset selection index for next step
|
|
189
211
|
const nextStep = steps[step + 1];
|
|
@@ -193,15 +215,18 @@ export function Config({ steps, state, debug, onFinished, onAborted }) {
|
|
|
193
215
|
}
|
|
194
216
|
};
|
|
195
217
|
const renderStepInput = (stepConfig, isCurrentStep) => {
|
|
218
|
+
const configKey = stepConfig.path || stepConfig.key;
|
|
219
|
+
// Use state values if not active (in timeline), otherwise use local values
|
|
220
|
+
const displayValue = !isActive && state?.values ? state.values[configKey] : values[configKey];
|
|
196
221
|
switch (stepConfig.type) {
|
|
197
222
|
case StepType.Text:
|
|
198
223
|
if (isCurrentStep) {
|
|
199
224
|
return (_jsx(TextStep, { value: inputValue, placeholder: stepConfig.value || undefined, validate: stepConfig.validate, onChange: setInputValue, onSubmit: handleSubmit }));
|
|
200
225
|
}
|
|
201
|
-
return _jsx(Text, { dimColor: true, children:
|
|
226
|
+
return (_jsx(Text, { dimColor: true, wrap: "truncate-end", children: displayValue || '' }));
|
|
202
227
|
case StepType.Selection: {
|
|
203
228
|
if (!isCurrentStep) {
|
|
204
|
-
const selectedOption = stepConfig.options.find((opt) => opt.value ===
|
|
229
|
+
const selectedOption = stepConfig.options.find((opt) => opt.value === displayValue);
|
|
205
230
|
return _jsx(Text, { dimColor: true, children: selectedOption?.label || '' });
|
|
206
231
|
}
|
|
207
232
|
return (_jsx(SelectionStep, { options: stepConfig.options, selectedIndex: selectedIndex, isCurrentStep: isCurrentStep }));
|
|
@@ -212,14 +237,14 @@ export function Config({ steps, state, debug, onFinished, onAborted }) {
|
|
|
212
237
|
}
|
|
213
238
|
}
|
|
214
239
|
};
|
|
215
|
-
return (_jsx(Box, { flexDirection: "column", children: steps.map((stepConfig, index) => {
|
|
216
|
-
const isCurrentStep = index === step &&
|
|
240
|
+
return (_jsx(Box, { flexDirection: "column", marginLeft: 1, children: steps.map((stepConfig, index) => {
|
|
241
|
+
const isCurrentStep = index === step && isActive;
|
|
217
242
|
const isCompleted = index < step;
|
|
218
|
-
const wasAborted = index === step &&
|
|
243
|
+
const wasAborted = index === step && !isActive;
|
|
219
244
|
const shouldShow = isCompleted || isCurrentStep || wasAborted;
|
|
220
245
|
if (!shouldShow) {
|
|
221
246
|
return null;
|
|
222
247
|
}
|
|
223
|
-
return (_jsxs(Box, { flexDirection: "column", marginTop: index === 0 ? 0 : 1, children: [_jsxs(Box, { children: [_jsx(Text, { children: stepConfig.description }), _jsx(Text, { children: ": " }), debug && stepConfig.path && (_jsxs(Text, { color: Colors.Type.Define, children: ['{', stepConfig.path, '}'] }))] }), _jsxs(Box, { children: [_jsx(Text, { children: " " }), _jsx(Text, { color: Colors.Action.Select, dimColor: !isCurrentStep, children: ">" }), _jsx(Text, { children: " " }), renderStepInput(stepConfig, isCurrentStep)] })] }, stepConfig.key));
|
|
248
|
+
return (_jsxs(Box, { flexDirection: "column", marginTop: index === 0 ? 0 : 1, children: [_jsxs(Box, { children: [_jsx(Text, { children: stepConfig.description }), _jsx(Text, { children: ": " }), debug && stepConfig.path && (_jsxs(Text, { color: Colors.Type.Define, children: ['{', stepConfig.path, '}'] }))] }), _jsxs(Box, { children: [_jsx(Text, { children: " " }), _jsx(Text, { color: Colors.Action.Select, dimColor: !isCurrentStep, children: ">" }), _jsx(Text, { children: " " }), renderStepInput(stepConfig, isCurrentStep)] })] }, stepConfig.path || stepConfig.key));
|
|
224
249
|
}) }));
|
|
225
250
|
}
|
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;
|
|
@@ -78,23 +75,30 @@ export function Introspect({ tasks, state, service, children, debug = false, onE
|
|
|
78
75
|
// Filter out internal capabilities when not in debug mode
|
|
79
76
|
if (!debug) {
|
|
80
77
|
capabilities = capabilities.filter((cap) => cap.name.toUpperCase() !== 'PLAN' &&
|
|
78
|
+
cap.name.toUpperCase() !== 'VALIDATE' &&
|
|
81
79
|
cap.name.toUpperCase() !== 'REPORT');
|
|
82
80
|
}
|
|
83
|
-
|
|
84
|
-
|
|
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();
|
|
85
90
|
}
|
|
86
91
|
}
|
|
87
92
|
catch (err) {
|
|
88
93
|
await ensureMinimumTime(startTime, MIN_PROCESSING_TIME);
|
|
89
94
|
if (mounted) {
|
|
90
95
|
const errorMessage = formatErrorMessage(err);
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
}
|
|
96
|
+
setError(errorMessage);
|
|
97
|
+
// Save error state
|
|
98
|
+
handlers?.updateState({
|
|
99
|
+
error: errorMessage,
|
|
100
|
+
});
|
|
101
|
+
handlers?.onError(errorMessage);
|
|
98
102
|
}
|
|
99
103
|
}
|
|
100
104
|
}
|
|
@@ -102,10 +106,10 @@ export function Introspect({ tasks, state, service, children, debug = false, onE
|
|
|
102
106
|
return () => {
|
|
103
107
|
mounted = false;
|
|
104
108
|
};
|
|
105
|
-
}, [tasks,
|
|
109
|
+
}, [tasks, isActive, service, debug, handlers]);
|
|
106
110
|
// Don't render wrapper when done and nothing to show
|
|
107
|
-
if (!
|
|
111
|
+
if (!isActive && !error && !children) {
|
|
108
112
|
return null;
|
|
109
113
|
}
|
|
110
|
-
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] }));
|
|
111
115
|
}
|