prompt-language-shell 0.8.4 → 0.8.6
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/configuration/io.js +85 -0
- package/dist/configuration/messages.js +30 -0
- package/dist/configuration/schema.js +167 -0
- package/dist/configuration/transformation.js +55 -0
- package/dist/configuration/types.js +30 -0
- package/dist/configuration/validation.js +52 -0
- package/dist/execution/handlers.js +135 -0
- package/dist/execution/processing.js +35 -0
- package/dist/execution/reducer.js +148 -0
- package/dist/execution/types.js +12 -0
- package/dist/execution/validation.js +12 -0
- package/dist/index.js +1 -1
- package/dist/services/anthropic.js +1 -1
- package/dist/services/colors.js +1 -1
- package/dist/services/components.js +35 -11
- package/dist/services/config-labels.js +15 -15
- package/dist/services/logger.js +2 -1
- package/dist/services/messages.js +32 -1
- package/dist/services/refinement.js +6 -6
- package/dist/services/router.js +43 -27
- package/dist/ui/Answer.js +36 -15
- package/dist/ui/Command.js +43 -23
- package/dist/ui/Component.js +147 -33
- package/dist/ui/Config.js +68 -78
- package/dist/ui/Confirm.js +34 -21
- package/dist/ui/Execute.js +107 -328
- package/dist/ui/Introspect.js +51 -24
- package/dist/ui/Label.js +1 -1
- package/dist/ui/Main.js +5 -1
- package/dist/ui/Refinement.js +8 -1
- package/dist/ui/Schedule.js +75 -52
- package/dist/ui/Validate.js +75 -77
- package/dist/ui/Workflow.js +50 -123
- package/package.json +1 -1
- package/dist/services/configuration.js +0 -409
package/dist/ui/Execute.js
CHANGED
|
@@ -2,182 +2,50 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { useCallback, useEffect, useReducer } from 'react';
|
|
3
3
|
import { Box, Text } from 'ink';
|
|
4
4
|
import { ComponentStatus, } from '../types/components.js';
|
|
5
|
-
import {
|
|
5
|
+
import { getTextColor } from '../services/colors.js';
|
|
6
6
|
import { useInput } from '../services/keyboard.js';
|
|
7
|
-
import { loadUserConfig } from '../services/loader.js';
|
|
8
7
|
import { formatErrorMessage } from '../services/messages.js';
|
|
9
|
-
import { replacePlaceholders } from '../services/resolver.js';
|
|
10
8
|
import { ExecutionStatus } from '../services/shell.js';
|
|
11
9
|
import { ensureMinimumTime } from '../services/timing.js';
|
|
12
|
-
import {
|
|
10
|
+
import { buildAbortedState, handleTaskCompletion, handleTaskFailure, } from '../execution/handlers.js';
|
|
11
|
+
import { processTasks } from '../execution/processing.js';
|
|
12
|
+
import { executeReducer, initialState } from '../execution/reducer.js';
|
|
13
|
+
import { ExecuteActionType } from '../execution/types.js';
|
|
14
|
+
import { Message } from './Message.js';
|
|
13
15
|
import { Spinner } from './Spinner.js';
|
|
14
16
|
import { Task } from './Task.js';
|
|
15
17
|
const MINIMUM_PROCESSING_TIME = 400;
|
|
18
|
+
export const ExecuteView = ({ state, status, onTaskComplete, onTaskAbort, onTaskError, }) => {
|
|
19
|
+
const isActive = status === ComponentStatus.Active;
|
|
20
|
+
const { error, taskInfos, message, completed, completionMessage } = state;
|
|
21
|
+
const hasProcessed = taskInfos.length > 0;
|
|
22
|
+
// Derive loading state from current conditions
|
|
23
|
+
const isLoading = isActive && taskInfos.length === 0 && !error && !hasProcessed;
|
|
24
|
+
const isExecuting = completed < taskInfos.length;
|
|
25
|
+
// Return null only when loading completes with no commands
|
|
26
|
+
if (!isActive && taskInfos.length === 0 && !error) {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
// Show completed steps when not active
|
|
30
|
+
const showTasks = !isActive && taskInfos.length > 0;
|
|
31
|
+
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: onTaskComplete, onAbort: onTaskAbort, onError: onTaskError }) }, index)))] })), completionMessage && !isActive && (_jsx(Box, { marginTop: 1, marginLeft: 1, children: _jsx(Text, { color: getTextColor(false), children: completionMessage }) })), error && _jsx(Message, { text: error, status: status })] }));
|
|
32
|
+
};
|
|
16
33
|
/**
|
|
17
|
-
*
|
|
18
|
-
* Throws an error if unresolved placeholders are found.
|
|
34
|
+
* Execute controller: Runs tasks sequentially
|
|
19
35
|
*/
|
|
20
|
-
function
|
|
21
|
-
const unresolvedPattern = /\{[^}]+\}/g;
|
|
22
|
-
const matches = command.match(unresolvedPattern);
|
|
23
|
-
if (matches && matches.length > 0) {
|
|
24
|
-
throw new Error(`Unresolved placeholders in command: ${matches.join(', ')}\nCommand: ${original}`);
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
function executeReducer(state, action) {
|
|
28
|
-
switch (action.type) {
|
|
29
|
-
case 'PROCESSING_COMPLETE':
|
|
30
|
-
return {
|
|
31
|
-
...state,
|
|
32
|
-
message: action.payload.message,
|
|
33
|
-
hasProcessed: true,
|
|
34
|
-
};
|
|
35
|
-
case 'COMMANDS_READY':
|
|
36
|
-
return {
|
|
37
|
-
...state,
|
|
38
|
-
message: action.payload.message,
|
|
39
|
-
summary: action.payload.summary,
|
|
40
|
-
taskInfos: action.payload.taskInfos,
|
|
41
|
-
completed: 0,
|
|
42
|
-
};
|
|
43
|
-
case 'PROCESSING_ERROR':
|
|
44
|
-
return {
|
|
45
|
-
...state,
|
|
46
|
-
error: action.payload.error,
|
|
47
|
-
hasProcessed: true,
|
|
48
|
-
};
|
|
49
|
-
case 'TASK_COMPLETE': {
|
|
50
|
-
const updatedTimes = [
|
|
51
|
-
...state.taskExecutionTimes,
|
|
52
|
-
action.payload.elapsed,
|
|
53
|
-
];
|
|
54
|
-
const updatedTaskInfos = state.taskInfos.map((task, i) => i === action.payload.index
|
|
55
|
-
? {
|
|
56
|
-
...task,
|
|
57
|
-
status: ExecutionStatus.Success,
|
|
58
|
-
elapsed: action.payload.elapsed,
|
|
59
|
-
}
|
|
60
|
-
: task);
|
|
61
|
-
return {
|
|
62
|
-
...state,
|
|
63
|
-
taskInfos: updatedTaskInfos,
|
|
64
|
-
taskExecutionTimes: updatedTimes,
|
|
65
|
-
completed: action.payload.index + 1,
|
|
66
|
-
};
|
|
67
|
-
}
|
|
68
|
-
case 'ALL_TASKS_COMPLETE': {
|
|
69
|
-
const updatedTimes = [
|
|
70
|
-
...state.taskExecutionTimes,
|
|
71
|
-
action.payload.elapsed,
|
|
72
|
-
];
|
|
73
|
-
const updatedTaskInfos = state.taskInfos.map((task, i) => i === action.payload.index
|
|
74
|
-
? {
|
|
75
|
-
...task,
|
|
76
|
-
status: ExecutionStatus.Success,
|
|
77
|
-
elapsed: action.payload.elapsed,
|
|
78
|
-
}
|
|
79
|
-
: task);
|
|
80
|
-
const totalElapsed = updatedTimes.reduce((sum, time) => sum + time, 0);
|
|
81
|
-
const completion = `${action.payload.summaryText} in ${formatDuration(totalElapsed)}.`;
|
|
82
|
-
return {
|
|
83
|
-
...state,
|
|
84
|
-
taskInfos: updatedTaskInfos,
|
|
85
|
-
taskExecutionTimes: updatedTimes,
|
|
86
|
-
completed: action.payload.index + 1,
|
|
87
|
-
completionMessage: completion,
|
|
88
|
-
};
|
|
89
|
-
}
|
|
90
|
-
case 'TASK_ERROR_CRITICAL': {
|
|
91
|
-
const updatedTaskInfos = state.taskInfos.map((task, i) => i === action.payload.index
|
|
92
|
-
? { ...task, status: ExecutionStatus.Failed, elapsed: 0 }
|
|
93
|
-
: task);
|
|
94
|
-
return {
|
|
95
|
-
...state,
|
|
96
|
-
taskInfos: updatedTaskInfos,
|
|
97
|
-
error: action.payload.error,
|
|
98
|
-
};
|
|
99
|
-
}
|
|
100
|
-
case 'TASK_ERROR_CONTINUE': {
|
|
101
|
-
const updatedTimes = [
|
|
102
|
-
...state.taskExecutionTimes,
|
|
103
|
-
action.payload.elapsed,
|
|
104
|
-
];
|
|
105
|
-
const updatedTaskInfos = state.taskInfos.map((task, i) => i === action.payload.index
|
|
106
|
-
? {
|
|
107
|
-
...task,
|
|
108
|
-
status: ExecutionStatus.Failed,
|
|
109
|
-
elapsed: action.payload.elapsed,
|
|
110
|
-
}
|
|
111
|
-
: task);
|
|
112
|
-
return {
|
|
113
|
-
...state,
|
|
114
|
-
taskInfos: updatedTaskInfos,
|
|
115
|
-
taskExecutionTimes: updatedTimes,
|
|
116
|
-
completed: action.payload.index + 1,
|
|
117
|
-
};
|
|
118
|
-
}
|
|
119
|
-
case 'LAST_TASK_ERROR': {
|
|
120
|
-
const updatedTimes = [
|
|
121
|
-
...state.taskExecutionTimes,
|
|
122
|
-
action.payload.elapsed,
|
|
123
|
-
];
|
|
124
|
-
const updatedTaskInfos = state.taskInfos.map((task, i) => i === action.payload.index
|
|
125
|
-
? {
|
|
126
|
-
...task,
|
|
127
|
-
status: ExecutionStatus.Failed,
|
|
128
|
-
elapsed: action.payload.elapsed,
|
|
129
|
-
}
|
|
130
|
-
: task);
|
|
131
|
-
const totalElapsed = updatedTimes.reduce((sum, time) => sum + time, 0);
|
|
132
|
-
const completion = `${action.payload.summaryText} in ${formatDuration(totalElapsed)}.`;
|
|
133
|
-
return {
|
|
134
|
-
...state,
|
|
135
|
-
taskInfos: updatedTaskInfos,
|
|
136
|
-
taskExecutionTimes: updatedTimes,
|
|
137
|
-
completed: action.payload.index + 1,
|
|
138
|
-
completionMessage: completion,
|
|
139
|
-
};
|
|
140
|
-
}
|
|
141
|
-
case 'CANCEL_EXECUTION': {
|
|
142
|
-
const updatedTaskInfos = state.taskInfos.map((task, taskIndex) => {
|
|
143
|
-
if (taskIndex < action.payload.completed) {
|
|
144
|
-
return { ...task, status: ExecutionStatus.Success };
|
|
145
|
-
}
|
|
146
|
-
else if (taskIndex === action.payload.completed) {
|
|
147
|
-
return { ...task, status: ExecutionStatus.Aborted };
|
|
148
|
-
}
|
|
149
|
-
else {
|
|
150
|
-
return { ...task, status: ExecutionStatus.Cancelled };
|
|
151
|
-
}
|
|
152
|
-
});
|
|
153
|
-
return {
|
|
154
|
-
...state,
|
|
155
|
-
taskInfos: updatedTaskInfos,
|
|
156
|
-
};
|
|
157
|
-
}
|
|
158
|
-
default:
|
|
159
|
-
return state;
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
export function Execute({ tasks, state, status, service, stateHandlers, lifecycleHandlers, errorHandlers, workflowHandlers, }) {
|
|
36
|
+
export function Execute({ tasks, status, service, requestHandlers, lifecycleHandlers, workflowHandlers, }) {
|
|
163
37
|
const isActive = status === ComponentStatus.Active;
|
|
164
|
-
const [localState, dispatch] = useReducer(executeReducer,
|
|
165
|
-
error: state?.error ?? null,
|
|
166
|
-
taskInfos: state?.taskInfos ?? [],
|
|
167
|
-
message: state?.message ?? '',
|
|
168
|
-
completed: state?.completed ?? 0,
|
|
169
|
-
hasProcessed: false,
|
|
170
|
-
taskExecutionTimes: state?.taskExecutionTimes ?? [],
|
|
171
|
-
completionMessage: state?.completionMessage ?? null,
|
|
172
|
-
summary: state?.summary ?? '',
|
|
173
|
-
});
|
|
38
|
+
const [localState, dispatch] = useReducer(executeReducer, initialState);
|
|
174
39
|
const { error, taskInfos, message, completed, hasProcessed, taskExecutionTimes, completionMessage, summary, } = localState;
|
|
175
40
|
// Derive loading state from current conditions
|
|
176
41
|
const isLoading = isActive && taskInfos.length === 0 && !error && !hasProcessed;
|
|
177
42
|
const isExecuting = completed < taskInfos.length;
|
|
178
43
|
// Handle cancel with useCallback to ensure we capture latest state
|
|
179
44
|
const handleCancel = useCallback(() => {
|
|
180
|
-
dispatch({
|
|
45
|
+
dispatch({
|
|
46
|
+
type: ExecuteActionType.CancelExecution,
|
|
47
|
+
payload: { completed },
|
|
48
|
+
});
|
|
181
49
|
// Get updated task infos after cancel
|
|
182
50
|
const updatedTaskInfos = taskInfos.map((task, taskIndex) => {
|
|
183
51
|
if (taskIndex < completed) {
|
|
@@ -190,7 +58,8 @@ export function Execute({ tasks, state, status, service, stateHandlers, lifecycl
|
|
|
190
58
|
return { ...task, status: ExecutionStatus.Cancelled };
|
|
191
59
|
}
|
|
192
60
|
});
|
|
193
|
-
|
|
61
|
+
// Expose final state
|
|
62
|
+
const finalState = {
|
|
194
63
|
message,
|
|
195
64
|
summary,
|
|
196
65
|
taskInfos: updatedTaskInfos,
|
|
@@ -198,16 +67,16 @@ export function Execute({ tasks, state, status, service, stateHandlers, lifecycl
|
|
|
198
67
|
taskExecutionTimes,
|
|
199
68
|
completionMessage: null,
|
|
200
69
|
error: null,
|
|
201
|
-
}
|
|
202
|
-
|
|
70
|
+
};
|
|
71
|
+
requestHandlers.onCompleted(finalState);
|
|
72
|
+
requestHandlers.onAborted('execution');
|
|
203
73
|
}, [
|
|
204
74
|
message,
|
|
205
75
|
summary,
|
|
206
76
|
taskInfos,
|
|
207
77
|
completed,
|
|
208
78
|
taskExecutionTimes,
|
|
209
|
-
|
|
210
|
-
errorHandlers,
|
|
79
|
+
requestHandlers,
|
|
211
80
|
]);
|
|
212
81
|
useInput((_, key) => {
|
|
213
82
|
if (key.escape && (isLoading || isExecuting) && isActive) {
|
|
@@ -223,33 +92,20 @@ export function Execute({ tasks, state, status, service, stateHandlers, lifecycl
|
|
|
223
92
|
async function process(svc) {
|
|
224
93
|
const startTime = Date.now();
|
|
225
94
|
try {
|
|
226
|
-
|
|
227
|
-
const userConfig = loadUserConfig();
|
|
228
|
-
// Format tasks for the execute tool and resolve placeholders
|
|
229
|
-
const taskDescriptions = tasks
|
|
230
|
-
.map((task) => {
|
|
231
|
-
const resolvedAction = replacePlaceholders(task.action, userConfig);
|
|
232
|
-
const params = task.params
|
|
233
|
-
? ` (params: ${JSON.stringify(task.params)})`
|
|
234
|
-
: '';
|
|
235
|
-
return `- ${resolvedAction}${params}`;
|
|
236
|
-
})
|
|
237
|
-
.join('\n');
|
|
238
|
-
// Call execute tool to get commands
|
|
239
|
-
const result = await svc.processWithTool(taskDescriptions, 'execute');
|
|
95
|
+
const result = await processTasks(tasks, svc);
|
|
240
96
|
await ensureMinimumTime(startTime, MINIMUM_PROCESSING_TIME);
|
|
241
97
|
if (!mounted)
|
|
242
98
|
return;
|
|
243
99
|
// Add debug components to timeline if present
|
|
244
100
|
if (result.debug?.length) {
|
|
245
|
-
workflowHandlers
|
|
101
|
+
workflowHandlers.addToTimeline(...result.debug);
|
|
246
102
|
}
|
|
247
|
-
if (
|
|
103
|
+
if (result.commands.length === 0) {
|
|
248
104
|
dispatch({
|
|
249
|
-
type:
|
|
105
|
+
type: ExecuteActionType.ProcessingComplete,
|
|
250
106
|
payload: { message: result.message },
|
|
251
107
|
});
|
|
252
|
-
|
|
108
|
+
const finalState = {
|
|
253
109
|
message: result.message,
|
|
254
110
|
summary: '',
|
|
255
111
|
taskInfos: [],
|
|
@@ -257,51 +113,45 @@ export function Execute({ tasks, state, status, service, stateHandlers, lifecycl
|
|
|
257
113
|
taskExecutionTimes: [],
|
|
258
114
|
completionMessage: null,
|
|
259
115
|
error: null,
|
|
260
|
-
}
|
|
261
|
-
|
|
116
|
+
};
|
|
117
|
+
requestHandlers.onCompleted(finalState);
|
|
118
|
+
lifecycleHandlers.completeActive();
|
|
262
119
|
return;
|
|
263
120
|
}
|
|
264
|
-
//
|
|
265
|
-
const
|
|
266
|
-
const resolved = replacePlaceholders(cmd.command, userConfig);
|
|
267
|
-
validatePlaceholderResolution(resolved, cmd.command);
|
|
268
|
-
return { ...cmd, command: resolved };
|
|
269
|
-
});
|
|
270
|
-
// Set message, summary, and create task infos
|
|
271
|
-
const newMessage = result.message;
|
|
272
|
-
const newSummary = result.summary || '';
|
|
273
|
-
const infos = resolvedCommands.map((cmd, index) => ({
|
|
121
|
+
// Create task infos from commands
|
|
122
|
+
const infos = result.commands.map((cmd, index) => ({
|
|
274
123
|
label: tasks[index]?.action,
|
|
275
124
|
command: cmd,
|
|
276
125
|
}));
|
|
277
126
|
dispatch({
|
|
278
|
-
type:
|
|
127
|
+
type: ExecuteActionType.CommandsReady,
|
|
279
128
|
payload: {
|
|
280
|
-
message:
|
|
281
|
-
summary:
|
|
129
|
+
message: result.message,
|
|
130
|
+
summary: result.summary,
|
|
282
131
|
taskInfos: infos,
|
|
283
132
|
},
|
|
284
133
|
});
|
|
285
134
|
// Update state after AI processing
|
|
286
|
-
|
|
287
|
-
message:
|
|
288
|
-
summary:
|
|
135
|
+
const finalState = {
|
|
136
|
+
message: result.message,
|
|
137
|
+
summary: result.summary,
|
|
289
138
|
taskInfos: infos,
|
|
290
139
|
completed: 0,
|
|
291
140
|
taskExecutionTimes: [],
|
|
292
141
|
completionMessage: null,
|
|
293
142
|
error: null,
|
|
294
|
-
}
|
|
143
|
+
};
|
|
144
|
+
requestHandlers.onCompleted(finalState);
|
|
295
145
|
}
|
|
296
146
|
catch (err) {
|
|
297
147
|
await ensureMinimumTime(startTime, MINIMUM_PROCESSING_TIME);
|
|
298
148
|
if (mounted) {
|
|
299
149
|
const errorMessage = formatErrorMessage(err);
|
|
300
150
|
dispatch({
|
|
301
|
-
type:
|
|
151
|
+
type: ExecuteActionType.ProcessingError,
|
|
302
152
|
payload: { error: errorMessage },
|
|
303
153
|
});
|
|
304
|
-
|
|
154
|
+
const finalState = {
|
|
305
155
|
message: '',
|
|
306
156
|
summary: '',
|
|
307
157
|
taskInfos: [],
|
|
@@ -309,8 +159,9 @@ export function Execute({ tasks, state, status, service, stateHandlers, lifecycl
|
|
|
309
159
|
taskExecutionTimes: [],
|
|
310
160
|
completionMessage: null,
|
|
311
161
|
error: errorMessage,
|
|
312
|
-
}
|
|
313
|
-
|
|
162
|
+
};
|
|
163
|
+
requestHandlers.onCompleted(finalState);
|
|
164
|
+
requestHandlers.onError(errorMessage);
|
|
314
165
|
}
|
|
315
166
|
}
|
|
316
167
|
}
|
|
@@ -322,150 +173,78 @@ export function Execute({ tasks, state, status, service, stateHandlers, lifecycl
|
|
|
322
173
|
tasks,
|
|
323
174
|
isActive,
|
|
324
175
|
service,
|
|
325
|
-
|
|
176
|
+
requestHandlers,
|
|
326
177
|
lifecycleHandlers,
|
|
327
178
|
workflowHandlers,
|
|
328
|
-
errorHandlers,
|
|
329
179
|
taskInfos.length,
|
|
330
180
|
hasProcessed,
|
|
331
181
|
]);
|
|
332
182
|
// Handle task completion - move to next task
|
|
333
183
|
const handleTaskComplete = useCallback((index, _output, elapsed) => {
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
taskInfos: updatedTaskInfos,
|
|
345
|
-
completed: index + 1,
|
|
346
|
-
taskExecutionTimes: updatedTimes,
|
|
347
|
-
completionMessage: null,
|
|
348
|
-
error: null,
|
|
349
|
-
});
|
|
350
|
-
}
|
|
351
|
-
else {
|
|
352
|
-
// All tasks complete
|
|
353
|
-
const summaryText = summary.trim() || 'Execution completed';
|
|
354
|
-
dispatch({
|
|
355
|
-
type: 'ALL_TASKS_COMPLETE',
|
|
356
|
-
payload: { index, elapsed, summaryText },
|
|
357
|
-
});
|
|
358
|
-
const updatedTimes = [...taskExecutionTimes, elapsed];
|
|
359
|
-
const updatedTaskInfos = taskInfos.map((task, i) => i === index
|
|
360
|
-
? { ...task, status: ExecutionStatus.Success, elapsed }
|
|
361
|
-
: task);
|
|
362
|
-
const totalElapsed = updatedTimes.reduce((sum, time) => sum + time, 0);
|
|
363
|
-
const completion = `${summaryText} in ${formatDuration(totalElapsed)}.`;
|
|
364
|
-
stateHandlers?.updateState({
|
|
365
|
-
message,
|
|
366
|
-
summary,
|
|
367
|
-
taskInfos: updatedTaskInfos,
|
|
368
|
-
completed: index + 1,
|
|
369
|
-
taskExecutionTimes: updatedTimes,
|
|
370
|
-
completionMessage: completion,
|
|
371
|
-
error: null,
|
|
372
|
-
});
|
|
373
|
-
lifecycleHandlers?.completeActive();
|
|
184
|
+
const result = handleTaskCompletion(index, elapsed, {
|
|
185
|
+
taskInfos,
|
|
186
|
+
message,
|
|
187
|
+
summary,
|
|
188
|
+
taskExecutionTimes,
|
|
189
|
+
});
|
|
190
|
+
dispatch(result.action);
|
|
191
|
+
requestHandlers.onCompleted(result.finalState);
|
|
192
|
+
if (result.shouldComplete) {
|
|
193
|
+
lifecycleHandlers.completeActive();
|
|
374
194
|
}
|
|
375
195
|
}, [
|
|
376
196
|
taskInfos,
|
|
377
197
|
message,
|
|
378
|
-
lifecycleHandlers,
|
|
379
|
-
taskExecutionTimes,
|
|
380
198
|
summary,
|
|
381
|
-
|
|
199
|
+
taskExecutionTimes,
|
|
200
|
+
requestHandlers,
|
|
201
|
+
lifecycleHandlers,
|
|
382
202
|
]);
|
|
383
203
|
const handleTaskError = useCallback((index, error, elapsed) => {
|
|
384
|
-
const
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
summary,
|
|
395
|
-
taskInfos: updatedTaskInfos,
|
|
396
|
-
completed: index + 1,
|
|
397
|
-
taskExecutionTimes,
|
|
398
|
-
completionMessage: null,
|
|
399
|
-
error,
|
|
400
|
-
});
|
|
401
|
-
errorHandlers?.onError(error);
|
|
204
|
+
const result = handleTaskFailure(index, error, elapsed, {
|
|
205
|
+
taskInfos,
|
|
206
|
+
message,
|
|
207
|
+
summary,
|
|
208
|
+
taskExecutionTimes,
|
|
209
|
+
});
|
|
210
|
+
dispatch(result.action);
|
|
211
|
+
requestHandlers.onCompleted(result.finalState);
|
|
212
|
+
if (result.shouldReportError) {
|
|
213
|
+
requestHandlers.onError(error);
|
|
402
214
|
}
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
const updatedTimes = [...taskExecutionTimes, elapsed];
|
|
406
|
-
if (index < taskInfos.length - 1) {
|
|
407
|
-
dispatch({
|
|
408
|
-
type: 'TASK_ERROR_CONTINUE',
|
|
409
|
-
payload: { index, elapsed },
|
|
410
|
-
});
|
|
411
|
-
stateHandlers?.updateState({
|
|
412
|
-
message,
|
|
413
|
-
summary,
|
|
414
|
-
taskInfos: updatedTaskInfos,
|
|
415
|
-
completed: index + 1,
|
|
416
|
-
taskExecutionTimes: updatedTimes,
|
|
417
|
-
completionMessage: null,
|
|
418
|
-
error: null,
|
|
419
|
-
});
|
|
420
|
-
}
|
|
421
|
-
else {
|
|
422
|
-
// Last task, complete execution
|
|
423
|
-
const summaryText = summary.trim() || 'Execution completed';
|
|
424
|
-
dispatch({
|
|
425
|
-
type: 'LAST_TASK_ERROR',
|
|
426
|
-
payload: { index, elapsed, summaryText },
|
|
427
|
-
});
|
|
428
|
-
const totalElapsed = updatedTimes.reduce((sum, time) => sum + time, 0);
|
|
429
|
-
const completion = `${summaryText} in ${formatDuration(totalElapsed)}.`;
|
|
430
|
-
stateHandlers?.updateState({
|
|
431
|
-
message,
|
|
432
|
-
summary,
|
|
433
|
-
taskInfos: updatedTaskInfos,
|
|
434
|
-
completed: index + 1,
|
|
435
|
-
taskExecutionTimes: updatedTimes,
|
|
436
|
-
completionMessage: completion,
|
|
437
|
-
error: null,
|
|
438
|
-
});
|
|
439
|
-
lifecycleHandlers?.completeActive();
|
|
440
|
-
}
|
|
215
|
+
if (result.shouldComplete) {
|
|
216
|
+
lifecycleHandlers.completeActive();
|
|
441
217
|
}
|
|
442
218
|
}, [
|
|
443
219
|
taskInfos,
|
|
444
220
|
message,
|
|
445
|
-
stateHandlers,
|
|
446
|
-
lifecycleHandlers,
|
|
447
|
-
errorHandlers,
|
|
448
|
-
taskExecutionTimes,
|
|
449
221
|
summary,
|
|
222
|
+
taskExecutionTimes,
|
|
223
|
+
requestHandlers,
|
|
224
|
+
lifecycleHandlers,
|
|
450
225
|
]);
|
|
451
226
|
const handleTaskAbort = useCallback((_index) => {
|
|
452
227
|
// Task was aborted - execution already stopped by Escape handler
|
|
453
228
|
// Just update state, don't call onAborted (already called at Execute level)
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
//
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
229
|
+
const finalState = buildAbortedState(taskInfos, message, summary, completed, taskExecutionTimes);
|
|
230
|
+
requestHandlers.onCompleted(finalState);
|
|
231
|
+
}, [
|
|
232
|
+
taskInfos,
|
|
233
|
+
message,
|
|
234
|
+
summary,
|
|
235
|
+
completed,
|
|
236
|
+
taskExecutionTimes,
|
|
237
|
+
requestHandlers,
|
|
238
|
+
]);
|
|
239
|
+
// Controller always renders View with current state
|
|
240
|
+
const viewState = {
|
|
241
|
+
error,
|
|
242
|
+
taskInfos,
|
|
243
|
+
message,
|
|
244
|
+
summary,
|
|
245
|
+
completed,
|
|
246
|
+
taskExecutionTimes,
|
|
247
|
+
completionMessage,
|
|
248
|
+
};
|
|
249
|
+
return (_jsx(ExecuteView, { tasks: tasks, state: viewState, status: status, onTaskComplete: handleTaskComplete, onTaskAbort: handleTaskAbort, onTaskError: handleTaskError }));
|
|
471
250
|
}
|