prompt-language-shell 0.7.8 → 0.8.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/services/colors.js +15 -8
- package/dist/services/components.js +27 -6
- package/dist/services/router.js +2 -3
- package/dist/services/shell.js +1 -0
- package/dist/ui/Answer.js +6 -1
- package/dist/ui/Command.js +4 -1
- package/dist/ui/Component.js +2 -2
- package/dist/ui/Config.js +31 -2
- package/dist/ui/Confirm.js +1 -1
- package/dist/ui/Execute.js +120 -28
- package/dist/ui/Feedback.js +1 -1
- package/dist/ui/Label.js +1 -1
- package/dist/ui/List.js +2 -1
- package/dist/ui/Schedule.js +1 -1
- package/dist/ui/Spinner.js +2 -1
- package/dist/ui/Subtask.js +14 -3
- package/dist/ui/Task.js +12 -8
- package/dist/ui/Validate.js +24 -18
- package/dist/ui/Workflow.js +1 -1
- package/package.json +12 -12
package/dist/services/colors.js
CHANGED
|
@@ -8,7 +8,6 @@ import { ExecutionStatus } from './shell.js';
|
|
|
8
8
|
export const Palette = {
|
|
9
9
|
White: '#ffffff',
|
|
10
10
|
AshGray: '#d0d0d0',
|
|
11
|
-
PaleGreen: '#a8dcbc',
|
|
12
11
|
Gray: '#888888',
|
|
13
12
|
DarkGray: '#666666',
|
|
14
13
|
CharcoalGray: '#282828',
|
|
@@ -16,8 +15,8 @@ export const Palette = {
|
|
|
16
15
|
LightGreen: '#65b595',
|
|
17
16
|
BrightGreen: '#3e9a3e',
|
|
18
17
|
Yellow: '#cccc5c',
|
|
19
|
-
LightYellow: '#d4d47a',
|
|
20
18
|
Orange: '#f48c80',
|
|
19
|
+
MediumOrange: '#d07560',
|
|
21
20
|
DarkOrange: '#ab5e40',
|
|
22
21
|
BurntOrange: '#cc7a5c',
|
|
23
22
|
Red: '#cc5c5c',
|
|
@@ -47,7 +46,7 @@ export const Colors = {
|
|
|
47
46
|
Status: {
|
|
48
47
|
Success: Palette.BrightGreen,
|
|
49
48
|
Error: Palette.Red,
|
|
50
|
-
Warning: Palette.
|
|
49
|
+
Warning: Palette.MediumOrange,
|
|
51
50
|
Info: Palette.Cyan,
|
|
52
51
|
},
|
|
53
52
|
Label: {
|
|
@@ -130,7 +129,7 @@ const taskColors = {
|
|
|
130
129
|
const feedbackColors = {
|
|
131
130
|
[FeedbackType.Info]: Colors.Status.Info,
|
|
132
131
|
[FeedbackType.Succeeded]: Colors.Status.Success,
|
|
133
|
-
[FeedbackType.Aborted]:
|
|
132
|
+
[FeedbackType.Aborted]: Palette.MediumOrange,
|
|
134
133
|
[FeedbackType.Failed]: Colors.Status.Error,
|
|
135
134
|
};
|
|
136
135
|
/**
|
|
@@ -220,6 +219,7 @@ export const STATUS_ICONS = {
|
|
|
220
219
|
[ExecutionStatus.Success]: '✓ ',
|
|
221
220
|
[ExecutionStatus.Failed]: '✗ ',
|
|
222
221
|
[ExecutionStatus.Aborted]: '⊘ ',
|
|
222
|
+
[ExecutionStatus.Cancelled]: '⊘ ',
|
|
223
223
|
};
|
|
224
224
|
/**
|
|
225
225
|
* Get colors for different execution status states.
|
|
@@ -249,7 +249,7 @@ export function getStatusColors(status) {
|
|
|
249
249
|
case ExecutionStatus.Success:
|
|
250
250
|
return {
|
|
251
251
|
icon: Colors.Status.Success,
|
|
252
|
-
description:
|
|
252
|
+
description: Palette.AshGray,
|
|
253
253
|
command: Palette.Gray,
|
|
254
254
|
symbol: Palette.Gray,
|
|
255
255
|
};
|
|
@@ -262,10 +262,17 @@ export function getStatusColors(status) {
|
|
|
262
262
|
};
|
|
263
263
|
case ExecutionStatus.Aborted:
|
|
264
264
|
return {
|
|
265
|
-
icon: Palette.
|
|
266
|
-
description:
|
|
267
|
-
command: Palette.
|
|
265
|
+
icon: Palette.MediumOrange,
|
|
266
|
+
description: Palette.Gray,
|
|
267
|
+
command: Palette.MediumOrange,
|
|
268
268
|
symbol: Palette.Gray,
|
|
269
269
|
};
|
|
270
|
+
case ExecutionStatus.Cancelled:
|
|
271
|
+
return {
|
|
272
|
+
icon: Palette.DarkGray,
|
|
273
|
+
description: Palette.DarkGray,
|
|
274
|
+
command: Palette.DarkGray,
|
|
275
|
+
symbol: Palette.DarkGray,
|
|
276
|
+
};
|
|
270
277
|
}
|
|
271
278
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { randomUUID } from 'node:crypto';
|
|
2
2
|
import { existsSync, readFileSync } from 'node:fs';
|
|
3
|
-
import { ComponentName } from '../types/types.js';
|
|
4
|
-
import { ComponentStatus, } from '../types/components.js';
|
|
5
3
|
import { parse as parseYaml } from 'yaml';
|
|
4
|
+
import { ComponentStatus, } from '../types/components.js';
|
|
5
|
+
import { ComponentName } from '../types/types.js';
|
|
6
6
|
import { ConfigDefinitionType, getConfigPath, getConfigSchema, loadConfig, } from './configuration.js';
|
|
7
7
|
import { getConfirmationMessage } from './messages.js';
|
|
8
8
|
import { StepType } from '../ui/Config.js';
|
|
@@ -180,7 +180,11 @@ export function createConfigDefinition(onFinished, onAborted) {
|
|
|
180
180
|
id: randomUUID(),
|
|
181
181
|
name: ComponentName.Config,
|
|
182
182
|
status: ComponentStatus.Awaiting,
|
|
183
|
-
state: {
|
|
183
|
+
state: {
|
|
184
|
+
values: {},
|
|
185
|
+
completedStep: 0,
|
|
186
|
+
selectedIndex: 0,
|
|
187
|
+
},
|
|
184
188
|
props: {
|
|
185
189
|
steps: createConfigSteps(),
|
|
186
190
|
onFinished,
|
|
@@ -196,7 +200,11 @@ export function createConfigDefinitionWithKeys(keys, onFinished, onAborted) {
|
|
|
196
200
|
id: randomUUID(),
|
|
197
201
|
name: ComponentName.Config,
|
|
198
202
|
status: ComponentStatus.Awaiting,
|
|
199
|
-
state: {
|
|
203
|
+
state: {
|
|
204
|
+
values: {},
|
|
205
|
+
completedStep: 0,
|
|
206
|
+
selectedIndex: 0,
|
|
207
|
+
},
|
|
200
208
|
props: {
|
|
201
209
|
steps: createConfigStepsFromSchema(keys),
|
|
202
210
|
onFinished,
|
|
@@ -338,7 +346,15 @@ export function createExecuteDefinition(tasks, service) {
|
|
|
338
346
|
id: randomUUID(),
|
|
339
347
|
name: ComponentName.Execute,
|
|
340
348
|
status: ComponentStatus.Awaiting,
|
|
341
|
-
state: {
|
|
349
|
+
state: {
|
|
350
|
+
error: null,
|
|
351
|
+
message: '',
|
|
352
|
+
summary: '',
|
|
353
|
+
taskInfos: [],
|
|
354
|
+
completed: 0,
|
|
355
|
+
taskExecutionTimes: [],
|
|
356
|
+
completionMessage: null,
|
|
357
|
+
},
|
|
342
358
|
props: {
|
|
343
359
|
tasks,
|
|
344
360
|
service,
|
|
@@ -350,7 +366,12 @@ export function createValidateDefinition(missingConfig, userRequest, service, on
|
|
|
350
366
|
id: randomUUID(),
|
|
351
367
|
name: ComponentName.Validate,
|
|
352
368
|
status: ComponentStatus.Awaiting,
|
|
353
|
-
state: {
|
|
369
|
+
state: {
|
|
370
|
+
error: null,
|
|
371
|
+
completionMessage: null,
|
|
372
|
+
configRequirements: null,
|
|
373
|
+
validated: false,
|
|
374
|
+
},
|
|
354
375
|
props: {
|
|
355
376
|
missingConfig,
|
|
356
377
|
userRequest,
|
package/dist/services/router.js
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import { TaskType } from '../types/types.js';
|
|
1
|
+
import { FeedbackType, TaskType } from '../types/types.js';
|
|
2
2
|
import { createAnswerDefinition, createConfigDefinitionWithKeys, createConfirmDefinition, createExecuteDefinition, createFeedback, createIntrospectDefinition, createMessage, createScheduleDefinition, createValidateDefinition, } from './components.js';
|
|
3
3
|
import { saveConfig, unflattenConfig } from './configuration.js';
|
|
4
|
-
import { FeedbackType } from '../types/types.js';
|
|
5
|
-
import { validateExecuteTasks } from './validator.js';
|
|
6
4
|
import { getCancellationMessage, getMixedTaskTypesError, getUnknownRequestMessage, } from './messages.js';
|
|
5
|
+
import { validateExecuteTasks } from './validator.js';
|
|
7
6
|
/**
|
|
8
7
|
* Determine the operation name based on task types
|
|
9
8
|
*/
|
package/dist/services/shell.js
CHANGED
|
@@ -5,6 +5,7 @@ export var ExecutionStatus;
|
|
|
5
5
|
ExecutionStatus["Success"] = "success";
|
|
6
6
|
ExecutionStatus["Failed"] = "failed";
|
|
7
7
|
ExecutionStatus["Aborted"] = "aborted";
|
|
8
|
+
ExecutionStatus["Cancelled"] = "cancelled";
|
|
8
9
|
})(ExecutionStatus || (ExecutionStatus = {}));
|
|
9
10
|
export var ExecutionResult;
|
|
10
11
|
(function (ExecutionResult) {
|
package/dist/ui/Answer.js
CHANGED
|
@@ -40,7 +40,9 @@ export function Answer({ question, state, status, service, handlers, }) {
|
|
|
40
40
|
const answerText = result.answer || '';
|
|
41
41
|
setAnswer(answerText);
|
|
42
42
|
// Update component state so answer persists in timeline
|
|
43
|
-
handlers?.updateState({
|
|
43
|
+
handlers?.updateState({
|
|
44
|
+
answer: answerText,
|
|
45
|
+
});
|
|
44
46
|
// Signal completion
|
|
45
47
|
handlers?.completeActive();
|
|
46
48
|
}
|
|
@@ -49,6 +51,9 @@ export function Answer({ question, state, status, service, handlers, }) {
|
|
|
49
51
|
if (mounted) {
|
|
50
52
|
const errorMessage = formatErrorMessage(err);
|
|
51
53
|
setError(errorMessage);
|
|
54
|
+
handlers?.updateState({
|
|
55
|
+
error: errorMessage,
|
|
56
|
+
});
|
|
52
57
|
handlers?.onError(errorMessage);
|
|
53
58
|
}
|
|
54
59
|
}
|
package/dist/ui/Command.js
CHANGED
|
@@ -5,8 +5,8 @@ import { ComponentStatus, } from '../types/components.js';
|
|
|
5
5
|
import { TaskType } from '../types/types.js';
|
|
6
6
|
import { Colors } from '../services/colors.js';
|
|
7
7
|
import { addDebugToTimeline, createScheduleDefinition, } from '../services/components.js';
|
|
8
|
-
import { formatErrorMessage } from '../services/messages.js';
|
|
9
8
|
import { useInput } from '../services/keyboard.js';
|
|
9
|
+
import { formatErrorMessage } from '../services/messages.js';
|
|
10
10
|
import { handleRefinement } from '../services/refinement.js';
|
|
11
11
|
import { routeTasksWithConfirm } from '../services/router.js';
|
|
12
12
|
import { ensureMinimumTime } from '../services/timing.js';
|
|
@@ -88,6 +88,9 @@ export function Command({ command, state, status, service, handlers, onAborted,
|
|
|
88
88
|
if (mounted) {
|
|
89
89
|
const errorMessage = formatErrorMessage(err);
|
|
90
90
|
setError(errorMessage);
|
|
91
|
+
handlers?.updateState({
|
|
92
|
+
error: errorMessage,
|
|
93
|
+
});
|
|
91
94
|
handlers?.onError(errorMessage);
|
|
92
95
|
}
|
|
93
96
|
}
|
package/dist/ui/Component.js
CHANGED
|
@@ -3,16 +3,16 @@ import { memo } from 'react';
|
|
|
3
3
|
import { ComponentName } from '../types/types.js';
|
|
4
4
|
import { Answer } from './Answer.js';
|
|
5
5
|
import { Command } from './Command.js';
|
|
6
|
-
import { Confirm } from './Confirm.js';
|
|
7
6
|
import { Config } from './Config.js';
|
|
7
|
+
import { Confirm } from './Confirm.js';
|
|
8
8
|
import { Debug } from './Debug.js';
|
|
9
9
|
import { Execute } from './Execute.js';
|
|
10
10
|
import { Feedback } from './Feedback.js';
|
|
11
11
|
import { Introspect } from './Introspect.js';
|
|
12
12
|
import { Message } from './Message.js';
|
|
13
|
-
import { Schedule } from './Schedule.js';
|
|
14
13
|
import { Refinement } from './Refinement.js';
|
|
15
14
|
import { Report } from './Report.js';
|
|
15
|
+
import { Schedule } from './Schedule.js';
|
|
16
16
|
import { Validate } from './Validate.js';
|
|
17
17
|
import { Welcome } from './Welcome.js';
|
|
18
18
|
export const Component = memo(function Component({ def, debug, }) {
|
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 { useState } from 'react';
|
|
2
|
+
import { useEffect, useState } from 'react';
|
|
3
3
|
import { Box, Text, useFocus } from 'ink';
|
|
4
4
|
import TextInput from 'ink-text-input';
|
|
5
5
|
import { ComponentStatus } from '../types/components.js';
|
|
@@ -17,6 +17,10 @@ function TextStep({ value, placeholder, validate, onChange, onSubmit, }) {
|
|
|
17
17
|
const [inputValue, setInputValue] = useState(value);
|
|
18
18
|
const [validationFailed, setValidationFailed] = useState(false);
|
|
19
19
|
const { isFocused } = useFocus({ autoFocus: true });
|
|
20
|
+
// Sync internal state with prop changes
|
|
21
|
+
useEffect(() => {
|
|
22
|
+
setInputValue(value);
|
|
23
|
+
}, [value]);
|
|
20
24
|
const handleChange = (newValue) => {
|
|
21
25
|
setInputValue(newValue);
|
|
22
26
|
onChange(newValue);
|
|
@@ -92,8 +96,20 @@ export function Config({ steps, state, status, debug = DebugLevel.None, handlers
|
|
|
92
96
|
});
|
|
93
97
|
return initial;
|
|
94
98
|
});
|
|
95
|
-
const [inputValue, setInputValue] = useState(
|
|
99
|
+
const [inputValue, setInputValue] = useState(() => {
|
|
100
|
+
// Initialize with the current step's value if available
|
|
101
|
+
if (isActive && step < steps.length) {
|
|
102
|
+
const stepConfig = steps[step];
|
|
103
|
+
const configKey = stepConfig.path || stepConfig.key;
|
|
104
|
+
return values[configKey] || '';
|
|
105
|
+
}
|
|
106
|
+
return '';
|
|
107
|
+
});
|
|
96
108
|
const [selectedIndex, setSelectedIndex] = useState(() => {
|
|
109
|
+
// If not active, use saved state
|
|
110
|
+
if (!isActive && state?.selectedIndex !== undefined) {
|
|
111
|
+
return state.selectedIndex;
|
|
112
|
+
}
|
|
97
113
|
// Initialize selectedIndex based on current step's defaultIndex
|
|
98
114
|
if (isActive &&
|
|
99
115
|
step < steps.length &&
|
|
@@ -108,6 +124,16 @@ export function Config({ steps, state, status, debug = DebugLevel.None, handlers
|
|
|
108
124
|
}
|
|
109
125
|
return value.replace(/\n/g, '').trim();
|
|
110
126
|
};
|
|
127
|
+
// Update inputValue when step changes
|
|
128
|
+
useEffect(() => {
|
|
129
|
+
if (isActive && step < steps.length) {
|
|
130
|
+
const stepConfig = steps[step];
|
|
131
|
+
const configKey = stepConfig.path || stepConfig.key;
|
|
132
|
+
const value = values[configKey] || '';
|
|
133
|
+
setInputValue(value);
|
|
134
|
+
}
|
|
135
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
136
|
+
}, [step, isActive, steps]);
|
|
111
137
|
useInput((_, key) => {
|
|
112
138
|
if (!isActive || step >= steps.length)
|
|
113
139
|
return;
|
|
@@ -137,6 +163,7 @@ export function Config({ steps, state, status, debug = DebugLevel.None, handlers
|
|
|
137
163
|
handlers?.updateState({
|
|
138
164
|
values,
|
|
139
165
|
completedStep: step,
|
|
166
|
+
selectedIndex,
|
|
140
167
|
});
|
|
141
168
|
if (onAborted) {
|
|
142
169
|
onAborted('configuration');
|
|
@@ -197,6 +224,7 @@ export function Config({ steps, state, status, debug = DebugLevel.None, handlers
|
|
|
197
224
|
const stateUpdate = {
|
|
198
225
|
values: newValues,
|
|
199
226
|
completedStep: steps.length,
|
|
227
|
+
selectedIndex,
|
|
200
228
|
};
|
|
201
229
|
handlers?.updateState(stateUpdate);
|
|
202
230
|
// Call onFinished callback and handle result
|
|
@@ -219,6 +247,7 @@ export function Config({ steps, state, status, debug = DebugLevel.None, handlers
|
|
|
219
247
|
const stateUpdate = {
|
|
220
248
|
values: newValues,
|
|
221
249
|
completedStep: step + 1,
|
|
250
|
+
selectedIndex,
|
|
222
251
|
};
|
|
223
252
|
handlers?.updateState(stateUpdate);
|
|
224
253
|
const nextStep = step + 1;
|
package/dist/ui/Confirm.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useState } from 'react';
|
|
3
3
|
import { Box, Text } from 'ink';
|
|
4
|
-
import { ComponentStatus
|
|
4
|
+
import { ComponentStatus } from '../types/components.js';
|
|
5
5
|
import { Colors, Palette } from '../services/colors.js';
|
|
6
6
|
import { useInput } from '../services/keyboard.js';
|
|
7
7
|
import { UserQuery } from './UserQuery.js';
|
package/dist/ui/Execute.js
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useCallback, useEffect, useState } from 'react';
|
|
3
3
|
import { Box, Text } from 'ink';
|
|
4
|
-
import { ComponentStatus } from '../types/components.js';
|
|
4
|
+
import { ComponentStatus, } from '../types/components.js';
|
|
5
5
|
import { Colors, getTextColor } from '../services/colors.js';
|
|
6
6
|
import { addDebugToTimeline } from '../services/components.js';
|
|
7
7
|
import { useInput } from '../services/keyboard.js';
|
|
8
|
+
import { loadUserConfig } from '../services/loader.js';
|
|
8
9
|
import { formatErrorMessage } from '../services/messages.js';
|
|
9
10
|
import { replacePlaceholders } from '../services/resolver.js';
|
|
10
|
-
import {
|
|
11
|
+
import { ExecutionStatus } from '../services/shell.js';
|
|
11
12
|
import { ensureMinimumTime } from '../services/timing.js';
|
|
12
13
|
import { formatDuration } from '../services/utils.js';
|
|
13
14
|
import { Spinner } from './Spinner.js';
|
|
@@ -18,19 +19,49 @@ export function Execute({ tasks, state, status, service, handlers, }) {
|
|
|
18
19
|
const [error, setError] = useState(state?.error ?? null);
|
|
19
20
|
const [taskInfos, setTaskInfos] = useState(state?.taskInfos ?? []);
|
|
20
21
|
const [message, setMessage] = useState(state?.message ?? '');
|
|
21
|
-
const [
|
|
22
|
+
const [completed, setCompleted] = useState(state?.completed ?? 0);
|
|
22
23
|
const [hasProcessed, setHasProcessed] = useState(false);
|
|
23
24
|
const [taskExecutionTimes, setTaskExecutionTimes] = useState(state?.taskExecutionTimes ?? []);
|
|
24
25
|
const [completionMessage, setCompletionMessage] = useState(state?.completionMessage ?? null);
|
|
25
26
|
const [summary, setSummary] = useState(state?.summary ?? '');
|
|
26
27
|
// Derive loading state from current conditions
|
|
27
28
|
const isLoading = isActive && taskInfos.length === 0 && !error && !hasProcessed;
|
|
28
|
-
const isExecuting =
|
|
29
|
+
const isExecuting = completed < taskInfos.length;
|
|
30
|
+
// Handle cancel with useCallback to ensure we capture latest state
|
|
31
|
+
const handleCancel = useCallback(() => {
|
|
32
|
+
// Mark tasks based on their status relative to completed:
|
|
33
|
+
// - Before completed: finished (Success)
|
|
34
|
+
// - At completed: interrupted (Aborted)
|
|
35
|
+
// - After completed: never started (Cancelled)
|
|
36
|
+
const updatedTaskInfos = taskInfos.map((task, taskIndex) => {
|
|
37
|
+
if (taskIndex < completed) {
|
|
38
|
+
// Tasks that completed before interruption
|
|
39
|
+
return { ...task, status: ExecutionStatus.Success };
|
|
40
|
+
}
|
|
41
|
+
else if (taskIndex === completed) {
|
|
42
|
+
// Task that was running when interrupted
|
|
43
|
+
return { ...task, status: ExecutionStatus.Aborted };
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
// Tasks that haven't started yet
|
|
47
|
+
return { ...task, status: ExecutionStatus.Cancelled };
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
setTaskInfos(updatedTaskInfos);
|
|
51
|
+
handlers?.updateState({
|
|
52
|
+
message,
|
|
53
|
+
summary,
|
|
54
|
+
taskInfos: updatedTaskInfos,
|
|
55
|
+
completed,
|
|
56
|
+
taskExecutionTimes,
|
|
57
|
+
completionMessage: null,
|
|
58
|
+
error: null,
|
|
59
|
+
});
|
|
60
|
+
handlers?.onAborted('execution');
|
|
61
|
+
}, [message, summary, taskInfos, completed, taskExecutionTimes, handlers]);
|
|
29
62
|
useInput((_, key) => {
|
|
30
63
|
if (key.escape && (isLoading || isExecuting) && isActive) {
|
|
31
|
-
|
|
32
|
-
setActiveTaskIndex(-1);
|
|
33
|
-
handlers?.onAborted('execution');
|
|
64
|
+
handleCancel();
|
|
34
65
|
}
|
|
35
66
|
}, { isActive: (isLoading || isExecuting) && isActive });
|
|
36
67
|
// Process tasks to get commands from AI
|
|
@@ -69,7 +100,12 @@ export function Execute({ tasks, state, status, service, handlers, }) {
|
|
|
69
100
|
setHasProcessed(true);
|
|
70
101
|
handlers?.updateState({
|
|
71
102
|
message: result.message,
|
|
103
|
+
summary: '',
|
|
72
104
|
taskInfos: [],
|
|
105
|
+
completed: 0,
|
|
106
|
+
taskExecutionTimes: [],
|
|
107
|
+
completionMessage: null,
|
|
108
|
+
error: null,
|
|
73
109
|
});
|
|
74
110
|
handlers?.completeActive();
|
|
75
111
|
return;
|
|
@@ -80,14 +116,26 @@ export function Execute({ tasks, state, status, service, handlers, }) {
|
|
|
80
116
|
command: replacePlaceholders(cmd.command, userConfig),
|
|
81
117
|
}));
|
|
82
118
|
// Set message, summary, and create task infos
|
|
83
|
-
|
|
84
|
-
|
|
119
|
+
const newMessage = result.message;
|
|
120
|
+
const newSummary = result.summary || '';
|
|
85
121
|
const infos = resolvedCommands.map((cmd, index) => ({
|
|
86
122
|
label: tasks[index]?.action,
|
|
87
123
|
command: cmd,
|
|
88
124
|
}));
|
|
125
|
+
setMessage(newMessage);
|
|
126
|
+
setSummary(newSummary);
|
|
89
127
|
setTaskInfos(infos);
|
|
90
|
-
|
|
128
|
+
setCompleted(0); // Start with first task
|
|
129
|
+
// Update state after AI processing
|
|
130
|
+
handlers?.updateState({
|
|
131
|
+
message: newMessage,
|
|
132
|
+
summary: newSummary,
|
|
133
|
+
taskInfos: infos,
|
|
134
|
+
completed: 0,
|
|
135
|
+
taskExecutionTimes: [],
|
|
136
|
+
completionMessage: null,
|
|
137
|
+
error: null,
|
|
138
|
+
});
|
|
91
139
|
}
|
|
92
140
|
catch (err) {
|
|
93
141
|
await ensureMinimumTime(startTime, MINIMUM_PROCESSING_TIME);
|
|
@@ -95,7 +143,15 @@ export function Execute({ tasks, state, status, service, handlers, }) {
|
|
|
95
143
|
const errorMessage = formatErrorMessage(err);
|
|
96
144
|
setError(errorMessage);
|
|
97
145
|
setHasProcessed(true);
|
|
98
|
-
handlers?.updateState({
|
|
146
|
+
handlers?.updateState({
|
|
147
|
+
message: '',
|
|
148
|
+
summary: '',
|
|
149
|
+
taskInfos: [],
|
|
150
|
+
completed: 0,
|
|
151
|
+
taskExecutionTimes: [],
|
|
152
|
+
completionMessage: null,
|
|
153
|
+
error: errorMessage,
|
|
154
|
+
});
|
|
99
155
|
handlers?.onError(errorMessage);
|
|
100
156
|
}
|
|
101
157
|
}
|
|
@@ -109,13 +165,26 @@ export function Execute({ tasks, state, status, service, handlers, }) {
|
|
|
109
165
|
const handleTaskComplete = useCallback((index, _output, elapsed) => {
|
|
110
166
|
const updatedTimes = [...taskExecutionTimes, elapsed];
|
|
111
167
|
setTaskExecutionTimes(updatedTimes);
|
|
168
|
+
// Update task with elapsed time and success status
|
|
169
|
+
const updatedTaskInfos = taskInfos.map((task, i) => i === index
|
|
170
|
+
? { ...task, status: ExecutionStatus.Success, elapsed }
|
|
171
|
+
: task);
|
|
172
|
+
setTaskInfos(updatedTaskInfos);
|
|
112
173
|
if (index < taskInfos.length - 1) {
|
|
113
174
|
// More tasks to execute
|
|
114
|
-
|
|
175
|
+
setCompleted(index + 1);
|
|
176
|
+
handlers?.updateState({
|
|
177
|
+
message,
|
|
178
|
+
summary,
|
|
179
|
+
taskInfos: updatedTaskInfos,
|
|
180
|
+
completed: index + 1,
|
|
181
|
+
taskExecutionTimes: updatedTimes,
|
|
182
|
+
completionMessage: null,
|
|
183
|
+
error: null,
|
|
184
|
+
});
|
|
115
185
|
}
|
|
116
186
|
else {
|
|
117
187
|
// All tasks complete
|
|
118
|
-
setActiveTaskIndex(-1);
|
|
119
188
|
const totalElapsed = updatedTimes.reduce((sum, time) => sum + time, 0);
|
|
120
189
|
const summaryText = summary?.trim() || 'Execution completed';
|
|
121
190
|
const completion = `${summaryText} in ${formatDuration(totalElapsed)}.`;
|
|
@@ -123,48 +192,67 @@ export function Execute({ tasks, state, status, service, handlers, }) {
|
|
|
123
192
|
handlers?.updateState({
|
|
124
193
|
message,
|
|
125
194
|
summary,
|
|
126
|
-
taskInfos,
|
|
127
|
-
|
|
195
|
+
taskInfos: updatedTaskInfos,
|
|
196
|
+
completed: index + 1,
|
|
128
197
|
taskExecutionTimes: updatedTimes,
|
|
129
198
|
completionMessage: completion,
|
|
199
|
+
error: null,
|
|
130
200
|
});
|
|
131
201
|
handlers?.completeActive();
|
|
132
202
|
}
|
|
133
203
|
}, [taskInfos, message, handlers, taskExecutionTimes, summary]);
|
|
134
|
-
const handleTaskError = useCallback((index, error) => {
|
|
204
|
+
const handleTaskError = useCallback((index, error, elapsed) => {
|
|
135
205
|
const task = taskInfos[index];
|
|
136
206
|
const isCritical = task?.command.critical !== false; // Default to true
|
|
207
|
+
// Update task with elapsed time and failed status
|
|
208
|
+
const updatedTaskInfos = taskInfos.map((task, i) => i === index
|
|
209
|
+
? { ...task, status: ExecutionStatus.Failed, elapsed }
|
|
210
|
+
: task);
|
|
211
|
+
setTaskInfos(updatedTaskInfos);
|
|
137
212
|
if (isCritical) {
|
|
138
213
|
// Critical failure - stop execution
|
|
139
|
-
setActiveTaskIndex(-1);
|
|
140
214
|
setError(error);
|
|
141
215
|
handlers?.updateState({
|
|
142
216
|
message,
|
|
143
|
-
|
|
144
|
-
|
|
217
|
+
summary,
|
|
218
|
+
taskInfos: updatedTaskInfos,
|
|
219
|
+
completed: index + 1,
|
|
220
|
+
taskExecutionTimes,
|
|
221
|
+
completionMessage: null,
|
|
145
222
|
error,
|
|
146
223
|
});
|
|
147
224
|
handlers?.onError(error);
|
|
148
225
|
}
|
|
149
226
|
else {
|
|
150
227
|
// Non-critical failure - continue to next task
|
|
228
|
+
const updatedTimes = [...taskExecutionTimes, elapsed];
|
|
229
|
+
setTaskExecutionTimes(updatedTimes);
|
|
151
230
|
if (index < taskInfos.length - 1) {
|
|
152
|
-
|
|
231
|
+
setCompleted(index + 1);
|
|
232
|
+
handlers?.updateState({
|
|
233
|
+
message,
|
|
234
|
+
summary,
|
|
235
|
+
taskInfos: updatedTaskInfos,
|
|
236
|
+
completed: index + 1,
|
|
237
|
+
taskExecutionTimes: updatedTimes,
|
|
238
|
+
completionMessage: null,
|
|
239
|
+
error: null,
|
|
240
|
+
});
|
|
153
241
|
}
|
|
154
242
|
else {
|
|
155
243
|
// Last task, complete execution
|
|
156
|
-
|
|
157
|
-
const totalElapsed = taskExecutionTimes.reduce((sum, time) => sum + time, 0);
|
|
244
|
+
const totalElapsed = updatedTimes.reduce((sum, time) => sum + time, 0);
|
|
158
245
|
const summaryText = summary?.trim() || 'Execution completed';
|
|
159
246
|
const completion = `${summaryText} in ${formatDuration(totalElapsed)}.`;
|
|
160
247
|
setCompletionMessage(completion);
|
|
161
248
|
handlers?.updateState({
|
|
162
249
|
message,
|
|
163
250
|
summary,
|
|
164
|
-
taskInfos,
|
|
165
|
-
|
|
166
|
-
taskExecutionTimes,
|
|
251
|
+
taskInfos: updatedTaskInfos,
|
|
252
|
+
completed: index + 1,
|
|
253
|
+
taskExecutionTimes: updatedTimes,
|
|
167
254
|
completionMessage: completion,
|
|
255
|
+
error: null,
|
|
168
256
|
});
|
|
169
257
|
handlers?.completeActive();
|
|
170
258
|
}
|
|
@@ -175,15 +263,19 @@ export function Execute({ tasks, state, status, service, handlers, }) {
|
|
|
175
263
|
// Just update state, don't call onAborted (already called at Execute level)
|
|
176
264
|
handlers?.updateState({
|
|
177
265
|
message,
|
|
266
|
+
summary,
|
|
178
267
|
taskInfos,
|
|
179
|
-
|
|
268
|
+
completed,
|
|
269
|
+
taskExecutionTimes,
|
|
270
|
+
completionMessage: null,
|
|
271
|
+
error: null,
|
|
180
272
|
});
|
|
181
|
-
}, [taskInfos, message, handlers]);
|
|
273
|
+
}, [taskInfos, message, summary, completed, taskExecutionTimes, handlers]);
|
|
182
274
|
// Return null only when loading completes with no commands
|
|
183
275
|
if (!isActive && taskInfos.length === 0 && !error) {
|
|
184
276
|
return null;
|
|
185
277
|
}
|
|
186
278
|
// Show completed steps when not active
|
|
187
279
|
const showTasks = !isActive && taskInfos.length > 0;
|
|
188
|
-
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 || showTasks) && (_jsxs(Box, { flexDirection: "column", marginLeft: 1, children: [message && (_jsxs(Box, { marginBottom: 1, gap: 1, children: [_jsx(Text, { color: getTextColor(isActive), children: message }), isExecuting && _jsx(Spinner, {})] })), taskInfos.map((taskInfo, index) => (_jsx(Box, { marginBottom: index < taskInfos.length - 1 ? 1 : 0, children: _jsx(Task, { label: taskInfo.label, command: taskInfo.command, isActive: isActive && index ===
|
|
280
|
+
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 || showTasks) && (_jsxs(Box, { flexDirection: "column", marginLeft: 1, children: [message && (_jsxs(Box, { marginBottom: 1, gap: 1, children: [_jsx(Text, { color: getTextColor(isActive), children: message }), isExecuting && _jsx(Spinner, {})] })), taskInfos.map((taskInfo, index) => (_jsx(Box, { marginBottom: index < taskInfos.length - 1 ? 1 : 0, children: _jsx(Task, { label: taskInfo.label, command: taskInfo.command, isActive: isActive && index === completed, index: index, initialStatus: taskInfo.status, initialElapsed: taskInfo.elapsed, onComplete: handleTaskComplete, onAbort: handleTaskAbort, onError: handleTaskError }) }, index)))] })), completionMessage && !isActive && (_jsx(Box, { marginTop: 1, marginLeft: 1, children: _jsx(Text, { color: getTextColor(false), children: completionMessage }) })), error && (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: Colors.Status.Error, children: ["Error: ", error] }) }))] }));
|
|
189
281
|
}
|
package/dist/ui/Feedback.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { Box, Text } from 'ink';
|
|
3
|
-
import { getFeedbackColor } from '../services/colors.js';
|
|
4
3
|
import { FeedbackType } from '../types/types.js';
|
|
4
|
+
import { getFeedbackColor } from '../services/colors.js';
|
|
5
5
|
function getSymbol(type) {
|
|
6
6
|
return {
|
|
7
7
|
[FeedbackType.Info]: 'ℹ',
|
package/dist/ui/Label.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Box, Text } from 'ink';
|
|
3
|
-
import { DebugLevel } from '../services/configuration.js';
|
|
4
3
|
import { getTaskColors, getTaskTypeLabel } from '../services/colors.js';
|
|
4
|
+
import { DebugLevel } from '../services/configuration.js';
|
|
5
5
|
import { Separator } from './Separator.js';
|
|
6
6
|
export function Label({ description, taskType, showType = false, isCurrent = false, debug = DebugLevel.None, }) {
|
|
7
7
|
const colors = getTaskColors(taskType, isCurrent);
|
package/dist/ui/List.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Box, Text } from 'ink';
|
|
3
|
+
import { Palette } from '../services/colors.js';
|
|
3
4
|
import { Separator } from './Separator.js';
|
|
4
5
|
export const List = ({ items, level = 0, highlightedIndex = null, highlightedParentIndex = null, showType = false, }) => {
|
|
5
6
|
const marginLeft = level > 0 ? 2 : 0;
|
|
@@ -21,7 +22,7 @@ export const List = ({ items, level = 0, highlightedIndex = null, highlightedPar
|
|
|
21
22
|
const markerColor = item.markerColor ||
|
|
22
23
|
(isHighlighted && item.type.highlightedColor
|
|
23
24
|
? item.type.highlightedColor
|
|
24
|
-
:
|
|
25
|
+
: Palette.White);
|
|
25
26
|
return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { children: [_jsx(Text, { color: markerColor, children: marker }), _jsx(Text, { color: descriptionColor, children: item.description.text }), showType && (_jsxs(_Fragment, { children: [_jsx(Separator, {}), _jsx(Text, { color: typeColor, children: item.type.text })] }))] }), item.children && item.children.length > 0 && (_jsx(List, { items: item.children, level: level + 1, highlightedIndex: shouldHighlightChildren ? highlightedIndex : null, showType: showType }))] }, index));
|
|
26
27
|
}) }));
|
|
27
28
|
};
|
package/dist/ui/Schedule.js
CHANGED
|
@@ -3,8 +3,8 @@ import { useEffect, useState } from 'react';
|
|
|
3
3
|
import { Box } from 'ink';
|
|
4
4
|
import { ComponentStatus } from '../types/components.js';
|
|
5
5
|
import { TaskType } from '../types/types.js';
|
|
6
|
-
import { DebugLevel } from '../services/configuration.js';
|
|
7
6
|
import { getTaskColors, getTaskTypeLabel } from '../services/colors.js';
|
|
7
|
+
import { DebugLevel } from '../services/configuration.js';
|
|
8
8
|
import { useInput } from '../services/keyboard.js';
|
|
9
9
|
import { Label } from './Label.js';
|
|
10
10
|
import { List } from './List.js';
|
package/dist/ui/Spinner.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { useEffect, useState } from 'react';
|
|
3
3
|
import { Text } from 'ink';
|
|
4
|
+
import { Palette } from '../services/colors.js';
|
|
4
5
|
const FRAMES = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
|
|
5
6
|
const INTERVAL = 80;
|
|
6
7
|
const CYCLE = FRAMES.length * INTERVAL;
|
|
@@ -18,5 +19,5 @@ export function Spinner() {
|
|
|
18
19
|
}, INTERVAL);
|
|
19
20
|
return () => clearInterval(timer);
|
|
20
21
|
}, []);
|
|
21
|
-
return _jsx(Text, { color:
|
|
22
|
+
return _jsx(Text, { color: Palette.Cyan, children: FRAMES[frame] });
|
|
22
23
|
}
|
package/dist/ui/Subtask.js
CHANGED
|
@@ -1,11 +1,22 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Box, Text } from 'ink';
|
|
3
3
|
import { getStatusColors, Palette, STATUS_ICONS } from '../services/colors.js';
|
|
4
|
-
import { formatDuration } from '../services/utils.js';
|
|
5
4
|
import { ExecutionStatus } from '../services/shell.js';
|
|
5
|
+
import { formatDuration } from '../services/utils.js';
|
|
6
6
|
import { Spinner } from './Spinner.js';
|
|
7
|
-
export function Subtask({ label, command, status, startTime, endTime, elapsed, }) {
|
|
7
|
+
export function Subtask({ label, command, status, isActive, startTime, endTime, elapsed, }) {
|
|
8
8
|
const colors = getStatusColors(status);
|
|
9
|
+
const isCancelled = status === ExecutionStatus.Cancelled;
|
|
10
|
+
const isAborted = status === ExecutionStatus.Aborted;
|
|
11
|
+
const shouldStrikethrough = isCancelled || isAborted;
|
|
12
|
+
const isFinished = status === ExecutionStatus.Success ||
|
|
13
|
+
status === ExecutionStatus.Failed ||
|
|
14
|
+
status === ExecutionStatus.Aborted;
|
|
9
15
|
const elapsedTime = elapsed ?? (startTime && endTime ? endTime - startTime : undefined);
|
|
10
|
-
|
|
16
|
+
// Apply strikethrough for cancelled and aborted tasks
|
|
17
|
+
const formatText = (text) => shouldStrikethrough ? text.split('').join('\u0336') + '\u0336' : text;
|
|
18
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { paddingLeft: 2, gap: 1, children: [_jsx(Text, { color: colors.icon, children: STATUS_ICONS[status] }), _jsx(Text, { color: colors.description, children: shouldStrikethrough
|
|
19
|
+
? formatText(label || command.description)
|
|
20
|
+
: label || command.description }), (isFinished || status === ExecutionStatus.Running) &&
|
|
21
|
+
elapsedTime !== undefined && (_jsxs(Text, { color: Palette.DarkGray, children: ["(", formatDuration(elapsedTime), ")"] }))] }), _jsxs(Box, { paddingLeft: 5, flexDirection: "row", children: [_jsx(Box, { children: _jsx(Text, { color: colors.symbol, children: "\u221F " }) }), _jsxs(Box, { gap: 1, children: [_jsx(Text, { color: colors.command, children: command.command }), status === ExecutionStatus.Running && _jsx(Spinner, {})] })] })] }));
|
|
11
22
|
}
|
package/dist/ui/Task.js
CHANGED
|
@@ -3,11 +3,11 @@ import { useEffect, useState } from 'react';
|
|
|
3
3
|
import { ExecutionStatus, executeCommand, } from '../services/shell.js';
|
|
4
4
|
import { calculateElapsed } from '../services/utils.js';
|
|
5
5
|
import { Subtask } from './Subtask.js';
|
|
6
|
-
export function Task({ label, command, isActive, index, onComplete, onAbort, onError, }) {
|
|
7
|
-
const [status, setStatus] = useState(ExecutionStatus.Pending);
|
|
6
|
+
export function Task({ label, command, isActive, index, initialStatus, initialElapsed, onComplete, onAbort, onError, }) {
|
|
7
|
+
const [status, setStatus] = useState(initialStatus ?? ExecutionStatus.Pending);
|
|
8
8
|
const [startTime, setStartTime] = useState();
|
|
9
9
|
const [endTime, setEndTime] = useState();
|
|
10
|
-
const [elapsed, setElapsed] = useState();
|
|
10
|
+
const [elapsed, setElapsed] = useState(initialElapsed);
|
|
11
11
|
const [currentElapsed, setCurrentElapsed] = useState(0);
|
|
12
12
|
// Update elapsed time while running
|
|
13
13
|
useEffect(() => {
|
|
@@ -23,7 +23,10 @@ export function Task({ label, command, isActive, index, onComplete, onAbort, onE
|
|
|
23
23
|
}, [status, startTime]);
|
|
24
24
|
// Execute command when becoming active
|
|
25
25
|
useEffect(() => {
|
|
26
|
-
if
|
|
26
|
+
// Don't execute if task is cancelled or if not active
|
|
27
|
+
if (!isActive ||
|
|
28
|
+
status === ExecutionStatus.Cancelled ||
|
|
29
|
+
status !== ExecutionStatus.Pending) {
|
|
27
30
|
return;
|
|
28
31
|
}
|
|
29
32
|
let mounted = true;
|
|
@@ -47,7 +50,7 @@ export function Task({ label, command, isActive, index, onComplete, onAbort, onE
|
|
|
47
50
|
onComplete?.(index, output, taskDuration);
|
|
48
51
|
}
|
|
49
52
|
else {
|
|
50
|
-
onError?.(index, output.errors || 'Command failed');
|
|
53
|
+
onError?.(index, output.errors || 'Command failed', taskDuration);
|
|
51
54
|
}
|
|
52
55
|
}
|
|
53
56
|
catch (err) {
|
|
@@ -55,9 +58,10 @@ export function Task({ label, command, isActive, index, onComplete, onAbort, onE
|
|
|
55
58
|
return;
|
|
56
59
|
const end = Date.now();
|
|
57
60
|
setEndTime(end);
|
|
58
|
-
|
|
61
|
+
const errorDuration = calculateElapsed(start);
|
|
62
|
+
setElapsed(errorDuration);
|
|
59
63
|
setStatus(ExecutionStatus.Failed);
|
|
60
|
-
onError?.(index, err instanceof Error ? err.message : 'Unknown error');
|
|
64
|
+
onError?.(index, err instanceof Error ? err.message : 'Unknown error', errorDuration);
|
|
61
65
|
}
|
|
62
66
|
}
|
|
63
67
|
execute();
|
|
@@ -77,5 +81,5 @@ export function Task({ label, command, isActive, index, onComplete, onAbort, onE
|
|
|
77
81
|
onAbort?.(index);
|
|
78
82
|
}
|
|
79
83
|
}, [isActive, status, startTime, index, onAbort]);
|
|
80
|
-
return (_jsx(Subtask, { label: label, command: command, status: status, startTime: startTime, endTime: endTime, elapsed: status === ExecutionStatus.Running ? currentElapsed : elapsed }));
|
|
84
|
+
return (_jsx(Subtask, { label: label, command: command, status: status, isActive: isActive, startTime: startTime, endTime: endTime, elapsed: status === ExecutionStatus.Running ? currentElapsed : elapsed }));
|
|
81
85
|
}
|
package/dist/ui/Validate.js
CHANGED
|
@@ -4,19 +4,19 @@ import { Box, Text } from 'ink';
|
|
|
4
4
|
import { ComponentStatus } from '../types/components.js';
|
|
5
5
|
import { TaskType } from '../types/types.js';
|
|
6
6
|
import { Colors, getTextColor } from '../services/colors.js';
|
|
7
|
-
import { addDebugToTimeline } from '../services/components.js';
|
|
7
|
+
import { addDebugToTimeline, createConfigStepsFromSchema, } from '../services/components.js';
|
|
8
|
+
import { DebugLevel, saveConfig, unflattenConfig, } from '../services/configuration.js';
|
|
8
9
|
import { useInput } from '../services/keyboard.js';
|
|
9
10
|
import { formatErrorMessage } from '../services/messages.js';
|
|
10
11
|
import { ensureMinimumTime } from '../services/timing.js';
|
|
11
|
-
import {
|
|
12
|
-
import { Config, StepType } from './Config.js';
|
|
12
|
+
import { Config } from './Config.js';
|
|
13
13
|
import { Spinner } from './Spinner.js';
|
|
14
14
|
const MIN_PROCESSING_TIME = 1000;
|
|
15
15
|
export function Validate({ missingConfig, userRequest, state, status, service, children, debug = DebugLevel.None, onError, onComplete, onAborted, handlers, }) {
|
|
16
16
|
const isActive = status === ComponentStatus.Active;
|
|
17
|
-
const [error, setError] = useState(null);
|
|
18
|
-
const [completionMessage, setCompletionMessage] = useState(null);
|
|
19
|
-
const [configRequirements, setConfigRequirements] = useState(null);
|
|
17
|
+
const [error, setError] = useState(state?.error ?? null);
|
|
18
|
+
const [completionMessage, setCompletionMessage] = useState(state?.completionMessage ?? null);
|
|
19
|
+
const [configRequirements, setConfigRequirements] = useState(state?.configRequirements ?? null);
|
|
20
20
|
const [showConfig, setShowConfig] = useState(false);
|
|
21
21
|
useInput((_, key) => {
|
|
22
22
|
if (key.escape && isActive && !showConfig) {
|
|
@@ -74,8 +74,10 @@ export function Validate({ missingConfig, userRequest, state, status, service, c
|
|
|
74
74
|
setConfigRequirements(withDescriptions);
|
|
75
75
|
// Save state after validation completes
|
|
76
76
|
handlers?.updateState({
|
|
77
|
+
completionMessage: message,
|
|
77
78
|
configRequirements: withDescriptions,
|
|
78
79
|
validated: true,
|
|
80
|
+
error: null,
|
|
79
81
|
});
|
|
80
82
|
}
|
|
81
83
|
}
|
|
@@ -83,16 +85,17 @@ export function Validate({ missingConfig, userRequest, state, status, service, c
|
|
|
83
85
|
await ensureMinimumTime(startTime, MIN_PROCESSING_TIME);
|
|
84
86
|
if (mounted) {
|
|
85
87
|
const errorMessage = formatErrorMessage(err);
|
|
88
|
+
setError(errorMessage);
|
|
86
89
|
// Save error state
|
|
87
90
|
handlers?.updateState({
|
|
88
91
|
error: errorMessage,
|
|
92
|
+
completionMessage: null,
|
|
93
|
+
configRequirements: null,
|
|
94
|
+
validated: false,
|
|
89
95
|
});
|
|
90
96
|
if (onError) {
|
|
91
97
|
onError(errorMessage);
|
|
92
98
|
}
|
|
93
|
-
else {
|
|
94
|
-
setError(errorMessage);
|
|
95
|
-
}
|
|
96
99
|
}
|
|
97
100
|
}
|
|
98
101
|
}
|
|
@@ -113,16 +116,19 @@ export function Validate({ missingConfig, userRequest, state, status, service, c
|
|
|
113
116
|
if (!isActive && !completionMessage && !error && !children) {
|
|
114
117
|
return null;
|
|
115
118
|
}
|
|
116
|
-
// Create ConfigSteps from requirements
|
|
119
|
+
// Create ConfigSteps from requirements using createConfigStepsFromSchema
|
|
120
|
+
// to load current values from config file, then override descriptions
|
|
117
121
|
const configSteps = configRequirements
|
|
118
|
-
?
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
122
|
+
? (() => {
|
|
123
|
+
const keys = configRequirements.map((req) => req.path);
|
|
124
|
+
const steps = createConfigStepsFromSchema(keys);
|
|
125
|
+
// Override descriptions with LLM-generated ones
|
|
126
|
+
return steps.map((step, index) => ({
|
|
127
|
+
...step,
|
|
128
|
+
description: configRequirements[index].description ||
|
|
129
|
+
configRequirements[index].path,
|
|
130
|
+
}));
|
|
131
|
+
})()
|
|
126
132
|
: null;
|
|
127
133
|
const handleConfigFinished = (config) => {
|
|
128
134
|
// Convert flat dotted keys to nested structure grouped by section
|
package/dist/ui/Workflow.js
CHANGED
|
@@ -5,8 +5,8 @@ import { ComponentStatus, } from '../types/components.js';
|
|
|
5
5
|
import { ComponentName, FeedbackType } from '../types/types.js';
|
|
6
6
|
import { createFeedback, isStateless, markAsDone, } from '../services/components.js';
|
|
7
7
|
import { DebugLevel } from '../services/configuration.js';
|
|
8
|
-
import { exitApp } from '../services/process.js';
|
|
9
8
|
import { getCancellationMessage } from '../services/messages.js';
|
|
9
|
+
import { exitApp } from '../services/process.js';
|
|
10
10
|
import { Component } from './Component.js';
|
|
11
11
|
export const Workflow = ({ initialQueue, debug }) => {
|
|
12
12
|
const [timeline, setTimeline] = useState([]);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "prompt-language-shell",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "Your personal command-line concierge. Ask politely, and it gets things done.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -47,22 +47,22 @@
|
|
|
47
47
|
},
|
|
48
48
|
"homepage": "https://github.com/aswitalski/pls#readme",
|
|
49
49
|
"dependencies": {
|
|
50
|
-
"@anthropic-ai/sdk": "^0.
|
|
51
|
-
"ink": "^6.
|
|
50
|
+
"@anthropic-ai/sdk": "^0.71.2",
|
|
51
|
+
"ink": "^6.6.0",
|
|
52
52
|
"ink-text-input": "^6.0.0",
|
|
53
|
-
"react": "^19.2.
|
|
54
|
-
"yaml": "^2.8.
|
|
53
|
+
"react": "^19.2.3",
|
|
54
|
+
"yaml": "^2.8.2"
|
|
55
55
|
},
|
|
56
56
|
"devDependencies": {
|
|
57
|
-
"@types/node": "^
|
|
58
|
-
"@types/react": "^19.2.
|
|
59
|
-
"@vitest/coverage-v8": "^4.0.
|
|
60
|
-
"eslint": "^9.39.
|
|
57
|
+
"@types/node": "^25.0.3",
|
|
58
|
+
"@types/react": "^19.2.7",
|
|
59
|
+
"@vitest/coverage-v8": "^4.0.16",
|
|
60
|
+
"eslint": "^9.39.2",
|
|
61
61
|
"husky": "^9.1.7",
|
|
62
62
|
"ink-testing-library": "^4.0.0",
|
|
63
|
-
"prettier": "^3.
|
|
63
|
+
"prettier": "^3.7.4",
|
|
64
64
|
"typescript": "^5.9.3",
|
|
65
|
-
"typescript-eslint": "^8.
|
|
66
|
-
"vitest": "^4.0.
|
|
65
|
+
"typescript-eslint": "^8.50.1",
|
|
66
|
+
"vitest": "^4.0.16"
|
|
67
67
|
}
|
|
68
68
|
}
|