prompt-language-shell 0.9.2 → 0.9.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/{ui/Main.js → Main.js} +12 -12
- package/dist/{ui → components}/Component.js +28 -26
- package/dist/{ui → components}/Workflow.js +14 -4
- package/dist/{ui → components/controllers}/Answer.js +18 -17
- package/dist/{ui → components/controllers}/Command.js +11 -18
- package/dist/{ui → components/controllers}/Config.js +8 -116
- package/dist/components/controllers/Confirm.js +42 -0
- package/dist/{ui → components/controllers}/Execute.js +75 -144
- package/dist/{ui → components/controllers}/Introspect.js +12 -28
- package/dist/components/controllers/Refinement.js +18 -0
- package/dist/components/controllers/Schedule.js +134 -0
- package/dist/{ui → components/controllers}/Validate.js +14 -32
- package/dist/components/views/Answer.js +28 -0
- package/dist/components/views/Command.js +11 -0
- package/dist/components/views/Config.js +115 -0
- package/dist/components/views/Confirm.js +24 -0
- package/dist/components/views/Debug.js +12 -0
- package/dist/components/views/Execute.js +60 -0
- package/dist/components/views/Feedback.js +8 -0
- package/dist/components/views/Introspect.js +17 -0
- package/dist/{ui → components/views}/Label.js +3 -3
- package/dist/{ui → components/views}/List.js +1 -1
- package/dist/{ui → components/views}/Output.js +2 -2
- package/dist/components/views/Refinement.js +9 -0
- package/dist/{ui → components/views}/Report.js +1 -1
- package/dist/components/views/Schedule.js +121 -0
- package/dist/{ui → components/views}/Separator.js +1 -1
- package/dist/{ui → components/views}/Spinner.js +1 -1
- package/dist/{ui → components/views}/Subtask.js +4 -4
- package/dist/components/views/Table.js +15 -0
- package/dist/components/views/Task.js +18 -0
- package/dist/components/views/Upcoming.js +30 -0
- package/dist/{ui → components/views}/UserQuery.js +1 -1
- package/dist/components/views/Validate.js +17 -0
- package/dist/{ui → components/views}/Welcome.js +1 -1
- package/dist/configuration/steps.js +1 -1
- package/dist/execution/handlers.js +19 -53
- package/dist/execution/reducer.js +26 -38
- package/dist/execution/runner.js +43 -25
- package/dist/execution/types.js +3 -4
- package/dist/execution/utils.js +1 -1
- package/dist/index.js +1 -1
- package/dist/services/anthropic.js +27 -31
- package/dist/services/colors.js +2 -1
- package/dist/services/logger.js +126 -13
- package/dist/services/messages.js +19 -0
- package/dist/services/parser.js +13 -5
- package/dist/services/refinement.js +8 -2
- package/dist/services/router.js +184 -89
- package/dist/services/shell.js +26 -6
- package/dist/services/skills.js +35 -7
- package/dist/services/timing.js +1 -0
- package/dist/skills/execute.md +15 -7
- package/dist/skills/schedule.md +155 -0
- package/dist/tools/execute.tool.js +0 -4
- package/dist/tools/schedule.tool.js +1 -1
- package/dist/types/schemas.js +0 -1
- package/package.json +4 -4
- package/dist/execution/hooks.js +0 -291
- package/dist/ui/Confirm.js +0 -62
- package/dist/ui/Debug.js +0 -7
- package/dist/ui/Feedback.js +0 -19
- package/dist/ui/Refinement.js +0 -23
- package/dist/ui/Schedule.js +0 -257
- package/dist/ui/Task.js +0 -11
- /package/dist/{ui → components/views}/Message.js +0 -0
- /package/dist/{ui → components/views}/Panel.js +0 -0
|
@@ -1,59 +1,20 @@
|
|
|
1
|
-
import { jsx as _jsx
|
|
2
|
-
import { useCallback, useEffect, useReducer, useRef
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
|
|
17
|
-
import { FeedbackType } from '../types/types.js';
|
|
18
|
-
import { Spinner } from './Spinner.js';
|
|
19
|
-
import { TaskView } from './Task.js';
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useCallback, useEffect, useReducer, useRef } from 'react';
|
|
3
|
+
import { ComponentStatus, } from '../../types/components.js';
|
|
4
|
+
import { useInput } from '../../services/keyboard.js';
|
|
5
|
+
import { formatErrorMessage, getExecutionErrorMessage, } from '../../services/messages.js';
|
|
6
|
+
import { ExecutionStatus } from '../../services/shell.js';
|
|
7
|
+
import { ELAPSED_UPDATE_INTERVAL, ensureMinimumTime, } from '../../services/timing.js';
|
|
8
|
+
import { handleTaskCompletion, handleTaskFailure, } from '../../execution/handlers.js';
|
|
9
|
+
import { processTasks } from '../../execution/processing.js';
|
|
10
|
+
import { executeReducer, initialState } from '../../execution/reducer.js';
|
|
11
|
+
import { executeTask } from '../../execution/runner.js';
|
|
12
|
+
import { ExecuteActionType } from '../../execution/types.js';
|
|
13
|
+
import { getCurrentTaskIndex } from '../../execution/utils.js';
|
|
14
|
+
import { createMessage } from '../../services/components.js';
|
|
15
|
+
import { ExecuteView } from '../views/Execute.js';
|
|
16
|
+
export { ExecuteView, mapStateToViewProps, } from '../views/Execute.js';
|
|
20
17
|
const MINIMUM_PROCESSING_TIME = 400;
|
|
21
|
-
const ELAPSED_UPDATE_INTERVAL = 1000;
|
|
22
|
-
/**
|
|
23
|
-
* Check if a task is finished (success, failed, or aborted)
|
|
24
|
-
*/
|
|
25
|
-
function isTaskFinished(task) {
|
|
26
|
-
return (task.status === ExecutionStatus.Success ||
|
|
27
|
-
task.status === ExecutionStatus.Failed ||
|
|
28
|
-
task.status === ExecutionStatus.Aborted);
|
|
29
|
-
}
|
|
30
|
-
/**
|
|
31
|
-
* Map ExecuteState to view props for rendering in timeline
|
|
32
|
-
*/
|
|
33
|
-
export function mapStateToViewProps(state, isActive) {
|
|
34
|
-
const taskViewData = state.tasks.map((task) => {
|
|
35
|
-
return {
|
|
36
|
-
label: task.label,
|
|
37
|
-
command: task.command,
|
|
38
|
-
status: task.status,
|
|
39
|
-
elapsed: task.elapsed,
|
|
40
|
-
stdout: task.stdout ?? '',
|
|
41
|
-
stderr: task.stderr ?? '',
|
|
42
|
-
isActive: false, // In timeline, no task is active
|
|
43
|
-
isFinished: isTaskFinished(task),
|
|
44
|
-
};
|
|
45
|
-
});
|
|
46
|
-
return {
|
|
47
|
-
isLoading: false,
|
|
48
|
-
isExecuting: false,
|
|
49
|
-
isActive,
|
|
50
|
-
error: state.error,
|
|
51
|
-
message: state.message,
|
|
52
|
-
tasks: taskViewData,
|
|
53
|
-
completionMessage: state.completionMessage,
|
|
54
|
-
showTasks: state.tasks.length > 0,
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
18
|
/**
|
|
58
19
|
* Create an ExecuteState with defaults
|
|
59
20
|
*/
|
|
@@ -67,32 +28,16 @@ function createExecuteState(overrides = {}) {
|
|
|
67
28
|
...overrides,
|
|
68
29
|
};
|
|
69
30
|
}
|
|
70
|
-
/**
|
|
71
|
-
* Execute view: Pure display component for task execution progress
|
|
72
|
-
*/
|
|
73
|
-
export const ExecuteView = ({ isLoading, isExecuting, isActive, error, message, tasks, completionMessage, showTasks, }) => {
|
|
74
|
-
// Return null only when loading completes with no commands
|
|
75
|
-
if (!isActive && tasks.length === 0 && !error) {
|
|
76
|
-
return null;
|
|
77
|
-
}
|
|
78
|
-
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, {})] })), tasks.map((task, index) => (_jsx(Box, { marginBottom: index < tasks.length - 1 ? 1 : 0, children: _jsx(TaskView, { label: task.label, command: task.command, status: task.status, elapsed: task.elapsed, stdout: task.stdout, stderr: task.stderr, isFinished: task.isFinished }) }, index)))] })), completionMessage && !isActive && (_jsx(Box, { marginTop: 1, marginLeft: 1, children: _jsx(Text, { color: getTextColor(false), children: completionMessage }) })), error && (_jsx(Box, { marginLeft: 1, children: _jsx(Text, { children: error }) }))] }));
|
|
79
|
-
};
|
|
80
31
|
/**
|
|
81
32
|
* Execute controller: Runs tasks sequentially and manages all execution state
|
|
82
33
|
*/
|
|
83
|
-
export function Execute({ tasks: inputTasks, status, service, requestHandlers, lifecycleHandlers, workflowHandlers, }) {
|
|
34
|
+
export function Execute({ tasks: inputTasks, status, service, upcoming, label, requestHandlers, lifecycleHandlers, workflowHandlers, }) {
|
|
84
35
|
const isActive = status === ComponentStatus.Active;
|
|
85
36
|
const [localState, dispatch] = useReducer(executeReducer, initialState);
|
|
86
|
-
// Live output state for currently executing task
|
|
87
|
-
const [liveOutput, setLiveOutput] = useState({
|
|
88
|
-
stdout: '',
|
|
89
|
-
stderr: '',
|
|
90
|
-
error: '',
|
|
91
|
-
});
|
|
92
|
-
const [liveElapsed, setLiveElapsed] = useState(0);
|
|
93
|
-
const [taskStartTime, setTaskStartTime] = useState(null);
|
|
94
37
|
// Track working directory across commands (persists cd changes)
|
|
95
38
|
const workdirRef = useRef(undefined);
|
|
39
|
+
// Ref to collect live output during execution (dispatched every second)
|
|
40
|
+
const outputRef = useRef({ stdout: '', stderr: '' });
|
|
96
41
|
// Ref to track if current task execution is cancelled
|
|
97
42
|
const cancelledRef = useRef(false);
|
|
98
43
|
const { error, tasks, message, hasProcessed, completionMessage, summary } = localState;
|
|
@@ -102,30 +47,45 @@ export function Execute({ tasks: inputTasks, status, service, requestHandlers, l
|
|
|
102
47
|
const isLoading = isActive && tasks.length === 0 && !error && !hasProcessed;
|
|
103
48
|
const isExecuting = isActive && currentTaskIndex < tasks.length;
|
|
104
49
|
const showTasks = !isActive && tasks.length > 0;
|
|
105
|
-
//
|
|
50
|
+
// Get current running task for progress updates
|
|
51
|
+
const runningTask = tasks.find((t) => t.status === ExecutionStatus.Running);
|
|
52
|
+
// Update reducer with progress every second while task is running
|
|
106
53
|
useEffect(() => {
|
|
107
|
-
if (!
|
|
54
|
+
if (!runningTask?.startTime || !isExecuting)
|
|
108
55
|
return;
|
|
56
|
+
const taskStartTime = runningTask.startTime;
|
|
109
57
|
const interval = setInterval(() => {
|
|
110
|
-
|
|
58
|
+
const elapsed = Date.now() - taskStartTime;
|
|
59
|
+
dispatch({
|
|
60
|
+
type: ExecuteActionType.TaskProgress,
|
|
61
|
+
payload: {
|
|
62
|
+
index: currentTaskIndex,
|
|
63
|
+
elapsed,
|
|
64
|
+
output: {
|
|
65
|
+
stdout: outputRef.current.stdout,
|
|
66
|
+
stderr: outputRef.current.stderr,
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
});
|
|
111
70
|
}, ELAPSED_UPDATE_INTERVAL);
|
|
112
71
|
return () => {
|
|
113
72
|
clearInterval(interval);
|
|
114
73
|
};
|
|
115
|
-
}, [
|
|
116
|
-
// Handle cancel
|
|
74
|
+
}, [runningTask?.startTime, isExecuting, currentTaskIndex]);
|
|
75
|
+
// Handle cancel - state already in reducer, just need to update final output
|
|
117
76
|
const handleCancel = useCallback(() => {
|
|
118
77
|
cancelledRef.current = true;
|
|
119
78
|
dispatch({ type: ExecuteActionType.CancelExecution });
|
|
120
|
-
// Build
|
|
121
|
-
const
|
|
79
|
+
// Build final state with current output for the running task
|
|
80
|
+
const updatedTasks = tasks.map((task) => {
|
|
122
81
|
if (task.status === ExecutionStatus.Running) {
|
|
123
82
|
return {
|
|
124
83
|
...task,
|
|
125
84
|
status: ExecutionStatus.Aborted,
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
85
|
+
output: {
|
|
86
|
+
stdout: outputRef.current.stdout,
|
|
87
|
+
stderr: outputRef.current.stderr,
|
|
88
|
+
},
|
|
129
89
|
};
|
|
130
90
|
}
|
|
131
91
|
else if (task.status === ExecutionStatus.Pending) {
|
|
@@ -136,11 +96,11 @@ export function Execute({ tasks: inputTasks, status, service, requestHandlers, l
|
|
|
136
96
|
const finalState = createExecuteState({
|
|
137
97
|
message,
|
|
138
98
|
summary,
|
|
139
|
-
tasks:
|
|
99
|
+
tasks: updatedTasks,
|
|
140
100
|
});
|
|
141
101
|
requestHandlers.onCompleted(finalState);
|
|
142
102
|
requestHandlers.onAborted('execution');
|
|
143
|
-
}, [message, summary, tasks,
|
|
103
|
+
}, [message, summary, tasks, requestHandlers]);
|
|
144
104
|
useInput((_, key) => {
|
|
145
105
|
if (key.escape && (isLoading || isExecuting)) {
|
|
146
106
|
handleCancel();
|
|
@@ -179,25 +139,26 @@ export function Execute({ tasks: inputTasks, status, service, requestHandlers, l
|
|
|
179
139
|
lifecycleHandlers.completeActive();
|
|
180
140
|
return;
|
|
181
141
|
}
|
|
182
|
-
// Create task
|
|
183
|
-
const
|
|
142
|
+
// Create task data from commands
|
|
143
|
+
const tasks = result.commands.map((cmd, index) => ({
|
|
184
144
|
label: inputTasks[index]?.action ?? cmd.description,
|
|
185
145
|
command: cmd,
|
|
186
146
|
status: ExecutionStatus.Pending,
|
|
187
147
|
elapsed: 0,
|
|
148
|
+
output: null,
|
|
188
149
|
}));
|
|
189
150
|
dispatch({
|
|
190
151
|
type: ExecuteActionType.CommandsReady,
|
|
191
152
|
payload: {
|
|
192
153
|
message: result.message,
|
|
193
154
|
summary: result.summary,
|
|
194
|
-
tasks
|
|
155
|
+
tasks,
|
|
195
156
|
},
|
|
196
157
|
});
|
|
197
158
|
requestHandlers.onCompleted(createExecuteState({
|
|
198
159
|
message: result.message,
|
|
199
160
|
summary: result.summary,
|
|
200
|
-
tasks
|
|
161
|
+
tasks,
|
|
201
162
|
}));
|
|
202
163
|
}
|
|
203
164
|
catch (err) {
|
|
@@ -243,36 +204,34 @@ export function Execute({ tasks: inputTasks, status, service, requestHandlers, l
|
|
|
243
204
|
// Mark task as started (running)
|
|
244
205
|
dispatch({
|
|
245
206
|
type: ExecuteActionType.TaskStarted,
|
|
246
|
-
payload: { index: currentTaskIndex },
|
|
207
|
+
payload: { index: currentTaskIndex, startTime: Date.now() },
|
|
247
208
|
});
|
|
248
|
-
// Reset
|
|
249
|
-
|
|
250
|
-
setLiveElapsed(0);
|
|
251
|
-
setTaskStartTime(Date.now());
|
|
209
|
+
// Reset output ref for new task
|
|
210
|
+
outputRef.current = { stdout: '', stderr: '' };
|
|
252
211
|
// Merge workdir into command
|
|
253
212
|
const command = workdirRef.current
|
|
254
213
|
? { ...currentTask.command, workdir: workdirRef.current }
|
|
255
214
|
: currentTask.command;
|
|
256
215
|
void executeTask(command, currentTaskIndex, {
|
|
257
|
-
|
|
216
|
+
onUpdate: (output) => {
|
|
258
217
|
if (!cancelledRef.current) {
|
|
259
|
-
|
|
218
|
+
outputRef.current = { stdout: output.stdout, stderr: output.stderr };
|
|
260
219
|
}
|
|
261
220
|
},
|
|
262
|
-
onComplete: (elapsed,
|
|
221
|
+
onComplete: (elapsed, execOutput) => {
|
|
263
222
|
if (cancelledRef.current)
|
|
264
223
|
return;
|
|
265
|
-
setTaskStartTime(null);
|
|
266
224
|
// Track working directory
|
|
267
|
-
if (
|
|
268
|
-
workdirRef.current =
|
|
225
|
+
if (execOutput.workdir) {
|
|
226
|
+
workdirRef.current = execOutput.workdir;
|
|
269
227
|
}
|
|
270
228
|
const tasksWithOutput = tasks.map((task, i) => i === currentTaskIndex
|
|
271
229
|
? {
|
|
272
230
|
...task,
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
231
|
+
output: {
|
|
232
|
+
stdout: execOutput.stdout,
|
|
233
|
+
stderr: execOutput.stderr,
|
|
234
|
+
},
|
|
276
235
|
}
|
|
277
236
|
: task);
|
|
278
237
|
const result = handleTaskCompletion(currentTaskIndex, elapsed, {
|
|
@@ -286,36 +245,32 @@ export function Execute({ tasks: inputTasks, status, service, requestHandlers, l
|
|
|
286
245
|
lifecycleHandlers.completeActive();
|
|
287
246
|
}
|
|
288
247
|
},
|
|
289
|
-
onError: (errorMsg,
|
|
248
|
+
onError: (errorMsg, execOutput) => {
|
|
290
249
|
if (cancelledRef.current)
|
|
291
250
|
return;
|
|
292
|
-
setTaskStartTime(null);
|
|
293
251
|
// Track working directory
|
|
294
|
-
if (
|
|
295
|
-
workdirRef.current =
|
|
252
|
+
if (execOutput.workdir) {
|
|
253
|
+
workdirRef.current = execOutput.workdir;
|
|
296
254
|
}
|
|
297
255
|
const tasksWithOutput = tasks.map((task, i) => i === currentTaskIndex
|
|
298
256
|
? {
|
|
299
257
|
...task,
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
258
|
+
output: {
|
|
259
|
+
stdout: execOutput.stdout,
|
|
260
|
+
stderr: execOutput.stderr,
|
|
261
|
+
},
|
|
262
|
+
error: execOutput.error || undefined,
|
|
303
263
|
}
|
|
304
264
|
: task);
|
|
305
|
-
const result = handleTaskFailure(currentTaskIndex, errorMsg,
|
|
265
|
+
const result = handleTaskFailure(currentTaskIndex, errorMsg, {
|
|
306
266
|
tasks: tasksWithOutput,
|
|
307
267
|
message,
|
|
308
268
|
summary,
|
|
309
269
|
});
|
|
310
270
|
dispatch(result.action);
|
|
311
271
|
requestHandlers.onCompleted(result.finalState);
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
workflowHandlers.addToQueue(createFeedback({ type: FeedbackType.Failed, message: errorMessage }));
|
|
315
|
-
}
|
|
316
|
-
if (result.shouldComplete) {
|
|
317
|
-
lifecycleHandlers.completeActive();
|
|
318
|
-
}
|
|
272
|
+
const errorMessage = getExecutionErrorMessage(errorMsg);
|
|
273
|
+
requestHandlers.onError(errorMessage);
|
|
319
274
|
},
|
|
320
275
|
});
|
|
321
276
|
}, [
|
|
@@ -329,29 +284,5 @@ export function Execute({ tasks: inputTasks, status, service, requestHandlers, l
|
|
|
329
284
|
lifecycleHandlers,
|
|
330
285
|
workflowHandlers,
|
|
331
286
|
]);
|
|
332
|
-
|
|
333
|
-
const taskViewData = tasks.map((task) => {
|
|
334
|
-
const isTaskActive = isActive && task.status === ExecutionStatus.Running;
|
|
335
|
-
const finished = isTaskFinished(task);
|
|
336
|
-
// Use live output for active task, stored output for finished tasks
|
|
337
|
-
const stdout = isTaskActive ? liveOutput.stdout : (task.stdout ?? '');
|
|
338
|
-
const stderr = isTaskActive ? liveOutput.stderr : (task.stderr ?? '');
|
|
339
|
-
// Use live elapsed for active running task
|
|
340
|
-
const elapsed = isTaskActive ? liveElapsed : task.elapsed;
|
|
341
|
-
// Merge workdir for active task
|
|
342
|
-
const command = isTaskActive && workdirRef.current
|
|
343
|
-
? { ...task.command, workdir: workdirRef.current }
|
|
344
|
-
: task.command;
|
|
345
|
-
return {
|
|
346
|
-
label: task.label,
|
|
347
|
-
command,
|
|
348
|
-
status: task.status,
|
|
349
|
-
elapsed,
|
|
350
|
-
stdout,
|
|
351
|
-
stderr,
|
|
352
|
-
isActive: isTaskActive,
|
|
353
|
-
isFinished: finished,
|
|
354
|
-
};
|
|
355
|
-
});
|
|
356
|
-
return (_jsx(ExecuteView, { isLoading: isLoading, isExecuting: isExecuting, isActive: isActive, error: error, message: message, tasks: taskViewData, completionMessage: completionMessage, showTasks: showTasks }));
|
|
287
|
+
return (_jsx(ExecuteView, { isLoading: isLoading, isExecuting: isExecuting, isActive: isActive, error: error, message: message, tasks: tasks, completionMessage: completionMessage, showTasks: showTasks, upcoming: upcoming, label: label }));
|
|
357
288
|
}
|
|
@@ -1,25 +1,15 @@
|
|
|
1
|
-
import { jsx as _jsx
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { useEffect, useState } from 'react';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
|
|
12
|
-
import { Spinner } from './Spinner.js';
|
|
3
|
+
import { ComponentStatus, } from '../../types/components.js';
|
|
4
|
+
import { Origin } from '../../types/types.js';
|
|
5
|
+
import { createReport } from '../../services/components.js';
|
|
6
|
+
import { DebugLevel } from '../../configuration/types.js';
|
|
7
|
+
import { useInput } from '../../services/keyboard.js';
|
|
8
|
+
import { formatErrorMessage } from '../../services/messages.js';
|
|
9
|
+
import { ensureMinimumTime } from '../../services/timing.js';
|
|
10
|
+
import { IntrospectView } from '../views/Introspect.js';
|
|
11
|
+
export { IntrospectView } from '../views/Introspect.js';
|
|
13
12
|
const MIN_PROCESSING_TIME = 1000;
|
|
14
|
-
export const IntrospectView = ({ state, status, children, }) => {
|
|
15
|
-
const isActive = status === ComponentStatus.Active;
|
|
16
|
-
const { error } = state;
|
|
17
|
-
// Don't render wrapper when done and nothing to show
|
|
18
|
-
if (!isActive && !error && !children) {
|
|
19
|
-
return null;
|
|
20
|
-
}
|
|
21
|
-
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] }));
|
|
22
|
-
};
|
|
23
13
|
/**
|
|
24
14
|
* Introspect controller: Lists capabilities via LLM
|
|
25
15
|
*/
|
|
@@ -27,7 +17,6 @@ export function Introspect({ tasks, status, service, children, debug = DebugLeve
|
|
|
27
17
|
const isActive = status === ComponentStatus.Active;
|
|
28
18
|
const [error, setError] = useState(null);
|
|
29
19
|
const [capabilities, setCapabilities] = useState(null);
|
|
30
|
-
const [message, setMessage] = useState(null);
|
|
31
20
|
useInput((input, key) => {
|
|
32
21
|
if (key.escape && isActive) {
|
|
33
22
|
requestHandlers.onAborted('introspection');
|
|
@@ -59,7 +48,6 @@ export function Introspect({ tasks, status, service, children, debug = DebugLeve
|
|
|
59
48
|
? result.capabilities.filter((cap) => cap.origin !== Origin.Indirect)
|
|
60
49
|
: result.capabilities;
|
|
61
50
|
setCapabilities(capabilities);
|
|
62
|
-
setMessage(message);
|
|
63
51
|
const finalState = {
|
|
64
52
|
error: null,
|
|
65
53
|
capabilities,
|
|
@@ -100,10 +88,6 @@ export function Introspect({ tasks, status, service, children, debug = DebugLeve
|
|
|
100
88
|
lifecycleHandlers,
|
|
101
89
|
workflowHandlers,
|
|
102
90
|
]);
|
|
103
|
-
const
|
|
104
|
-
|
|
105
|
-
capabilities: capabilities || [],
|
|
106
|
-
message,
|
|
107
|
-
};
|
|
108
|
-
return (_jsx(IntrospectView, { state: state, status: status, children: children }));
|
|
91
|
+
const hasCapabilities = capabilities !== null && capabilities.length > 0;
|
|
92
|
+
return (_jsx(IntrospectView, { status: status, hasCapabilities: hasCapabilities, error: error, children: children }));
|
|
109
93
|
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { ComponentStatus } from '../../types/components.js';
|
|
3
|
+
import { useInput } from '../../services/keyboard.js';
|
|
4
|
+
import { RefinementView } from '../views/Refinement.js';
|
|
5
|
+
export { RefinementView } from '../views/Refinement.js';
|
|
6
|
+
/**
|
|
7
|
+
* Refinement controller: Handles abort input
|
|
8
|
+
*/
|
|
9
|
+
export const Refinement = ({ text, status, onAborted }) => {
|
|
10
|
+
const isActive = status === ComponentStatus.Active;
|
|
11
|
+
useInput((_, key) => {
|
|
12
|
+
if (key.escape && isActive) {
|
|
13
|
+
onAborted('plan refinement');
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
}, { isActive });
|
|
17
|
+
return _jsx(RefinementView, { text: text, status: status });
|
|
18
|
+
};
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useState } from 'react';
|
|
3
|
+
import { ComponentStatus, } from '../../types/components.js';
|
|
4
|
+
import { TaskType } from '../../types/types.js';
|
|
5
|
+
import { DebugLevel } from '../../configuration/types.js';
|
|
6
|
+
import { useInput } from '../../services/keyboard.js';
|
|
7
|
+
import { ScheduleView } from '../views/Schedule.js';
|
|
8
|
+
export { ScheduleView, taskToListItem, } from '../views/Schedule.js';
|
|
9
|
+
/**
|
|
10
|
+
* Schedule controller: Manages task selection and navigation
|
|
11
|
+
*/
|
|
12
|
+
export function Schedule({ message, tasks, status, debug = DebugLevel.None, requestHandlers, lifecycleHandlers, onSelectionConfirmed, }) {
|
|
13
|
+
const isActive = status === ComponentStatus.Active;
|
|
14
|
+
const [highlightedIndex, setHighlightedIndex] = useState(null);
|
|
15
|
+
const [currentDefineGroupIndex, setCurrentDefineGroupIndex] = useState(0);
|
|
16
|
+
const [completedSelections, setCompletedSelections] = useState([]);
|
|
17
|
+
// Find all Define tasks
|
|
18
|
+
const defineTaskIndices = tasks
|
|
19
|
+
.map((t, idx) => (t.type === TaskType.Define ? idx : -1))
|
|
20
|
+
.filter((idx) => idx !== -1);
|
|
21
|
+
// Get the current active define task
|
|
22
|
+
const currentDefineTaskIndex = defineTaskIndices[currentDefineGroupIndex] ?? -1;
|
|
23
|
+
const defineTask = currentDefineTaskIndex >= 0 ? tasks[currentDefineTaskIndex] : null;
|
|
24
|
+
const optionsCount = Array.isArray(defineTask?.params?.options)
|
|
25
|
+
? defineTask.params.options.length
|
|
26
|
+
: 0;
|
|
27
|
+
const hasMoreGroups = currentDefineGroupIndex < defineTaskIndices.length - 1;
|
|
28
|
+
// If no DEFINE tasks, immediately confirm with all tasks
|
|
29
|
+
useEffect(() => {
|
|
30
|
+
if (isActive && defineTaskIndices.length === 0 && onSelectionConfirmed) {
|
|
31
|
+
// No selection needed - all tasks are concrete
|
|
32
|
+
const concreteTasks = tasks.filter((task) => task.type !== TaskType.Ignore && task.type !== TaskType.Discard);
|
|
33
|
+
// Expose final state
|
|
34
|
+
const finalState = {
|
|
35
|
+
highlightedIndex,
|
|
36
|
+
currentDefineGroupIndex,
|
|
37
|
+
completedSelections,
|
|
38
|
+
};
|
|
39
|
+
requestHandlers.onCompleted(finalState);
|
|
40
|
+
// Move Schedule to pending - callback will flush to timeline
|
|
41
|
+
lifecycleHandlers.completeActive();
|
|
42
|
+
void onSelectionConfirmed(concreteTasks);
|
|
43
|
+
}
|
|
44
|
+
}, [
|
|
45
|
+
isActive,
|
|
46
|
+
defineTaskIndices.length,
|
|
47
|
+
tasks,
|
|
48
|
+
onSelectionConfirmed,
|
|
49
|
+
lifecycleHandlers,
|
|
50
|
+
highlightedIndex,
|
|
51
|
+
currentDefineGroupIndex,
|
|
52
|
+
completedSelections,
|
|
53
|
+
requestHandlers,
|
|
54
|
+
]);
|
|
55
|
+
useInput((input, key) => {
|
|
56
|
+
// Don't handle input if not active or no define task
|
|
57
|
+
if (!isActive || !defineTask) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
if (key.escape) {
|
|
61
|
+
requestHandlers.onAborted('task selection');
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
if (key.downArrow) {
|
|
65
|
+
setHighlightedIndex((prev) => {
|
|
66
|
+
if (prev === null) {
|
|
67
|
+
return 0; // Select first
|
|
68
|
+
}
|
|
69
|
+
return (prev + 1) % optionsCount; // Wrap around
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
else if (key.upArrow) {
|
|
73
|
+
setHighlightedIndex((prev) => {
|
|
74
|
+
if (prev === null) {
|
|
75
|
+
return optionsCount - 1; // Select last
|
|
76
|
+
}
|
|
77
|
+
return (prev - 1 + optionsCount) % optionsCount; // Wrap around
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
else if (key.return && highlightedIndex !== null) {
|
|
81
|
+
// Record the selection for this group
|
|
82
|
+
const newCompletedSelections = [...completedSelections];
|
|
83
|
+
newCompletedSelections[currentDefineGroupIndex] = highlightedIndex;
|
|
84
|
+
setCompletedSelections(newCompletedSelections);
|
|
85
|
+
if (hasMoreGroups) {
|
|
86
|
+
// Advance to next group
|
|
87
|
+
const newGroupIndex = currentDefineGroupIndex + 1;
|
|
88
|
+
setCurrentDefineGroupIndex(newGroupIndex);
|
|
89
|
+
setHighlightedIndex(null);
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
// Clear highlight to show Execute color
|
|
93
|
+
setHighlightedIndex(null);
|
|
94
|
+
// Build refined task list with only selected options (no discarded or ignored ones)
|
|
95
|
+
const refinedTasks = [];
|
|
96
|
+
tasks.forEach((task, idx) => {
|
|
97
|
+
const defineGroupIndex = defineTaskIndices.indexOf(idx);
|
|
98
|
+
if (defineGroupIndex !== -1 &&
|
|
99
|
+
Array.isArray(task.params?.options)) {
|
|
100
|
+
// This is a Define task - only include the selected option
|
|
101
|
+
const options = task.params.options;
|
|
102
|
+
const selectedIndex = newCompletedSelections[defineGroupIndex];
|
|
103
|
+
const selectedOption = options[selectedIndex];
|
|
104
|
+
// Use the command from the selected option
|
|
105
|
+
refinedTasks.push({
|
|
106
|
+
action: selectedOption.command,
|
|
107
|
+
type: TaskType.Execute,
|
|
108
|
+
config: [],
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
else if (task.type !== TaskType.Ignore &&
|
|
112
|
+
task.type !== TaskType.Discard) {
|
|
113
|
+
// Regular task - keep as is, but skip Ignore and Discard tasks
|
|
114
|
+
refinedTasks.push(task);
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
// Expose final state
|
|
118
|
+
const finalState = {
|
|
119
|
+
highlightedIndex: null,
|
|
120
|
+
currentDefineGroupIndex,
|
|
121
|
+
completedSelections: newCompletedSelections,
|
|
122
|
+
};
|
|
123
|
+
requestHandlers.onCompleted(finalState);
|
|
124
|
+
// Move Schedule to pending - refinement will flush it to timeline
|
|
125
|
+
// before adding Command, ensuring correct order
|
|
126
|
+
lifecycleHandlers.completeActive();
|
|
127
|
+
if (onSelectionConfirmed) {
|
|
128
|
+
void onSelectionConfirmed(refinedTasks);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}, { isActive: isActive && defineTask !== null });
|
|
133
|
+
return (_jsx(ScheduleView, { status: status, message: message, tasks: tasks, highlightedIndex: highlightedIndex, currentDefineGroupIndex: currentDefineGroupIndex, completedSelections: completedSelections, debug: debug }));
|
|
134
|
+
}
|
|
@@ -1,28 +1,18 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { useEffect, useState } from 'react';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
|
|
15
|
-
import { Spinner } from './Spinner.js';
|
|
3
|
+
import { ComponentStatus, } from '../../types/components.js';
|
|
4
|
+
import { TaskType } from '../../types/types.js';
|
|
5
|
+
import { saveConfig } from '../../configuration/io.js';
|
|
6
|
+
import { createConfigStepsFromSchema } from '../../configuration/steps.js';
|
|
7
|
+
import { unflattenConfig } from '../../configuration/transformation.js';
|
|
8
|
+
import { createConfig, createMessage } from '../../services/components.js';
|
|
9
|
+
import { saveConfigLabels } from '../../configuration/labels.js';
|
|
10
|
+
import { useInput } from '../../services/keyboard.js';
|
|
11
|
+
import { formatErrorMessage, getUnresolvedPlaceholdersMessage, } from '../../services/messages.js';
|
|
12
|
+
import { ensureMinimumTime } from '../../services/timing.js';
|
|
13
|
+
import { ValidateView } from '../views/Validate.js';
|
|
14
|
+
export { ValidateView } from '../views/Validate.js';
|
|
16
15
|
const MIN_PROCESSING_TIME = 1000;
|
|
17
|
-
export const ValidateView = ({ state, status }) => {
|
|
18
|
-
const isActive = status === ComponentStatus.Active;
|
|
19
|
-
const { error, completionMessage } = state;
|
|
20
|
-
// Don't render when not active and nothing to show
|
|
21
|
-
if (!isActive && !completionMessage && !error) {
|
|
22
|
-
return null;
|
|
23
|
-
}
|
|
24
|
-
return (_jsxs(Box, { alignSelf: "flex-start", flexDirection: "column", children: [isActive && !completionMessage && !error && (_jsxs(Box, { marginLeft: 1, children: [_jsxs(Text, { color: getTextColor(isActive), children: ["Validating configuration requirements.", ' '] }), _jsx(Spinner, {})] })), completionMessage && (_jsx(Box, { marginLeft: 1, children: _jsx(Text, { color: getTextColor(isActive), children: completionMessage }) })), error && (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: Colors.Status.Error, children: ["Error: ", error] }) }))] }));
|
|
25
|
-
};
|
|
26
16
|
/**
|
|
27
17
|
* Validate controller: Validates missing config
|
|
28
18
|
*/
|
|
@@ -30,7 +20,6 @@ export function Validate({ missingConfig, userRequest, status, service, onError,
|
|
|
30
20
|
const isActive = status === ComponentStatus.Active;
|
|
31
21
|
const [error, setError] = useState(null);
|
|
32
22
|
const [completionMessage, setCompletionMessage] = useState(null);
|
|
33
|
-
const [configRequirements, setConfigRequirements] = useState([]);
|
|
34
23
|
useInput((_, key) => {
|
|
35
24
|
if (key.escape && isActive) {
|
|
36
25
|
onAborted('validation');
|
|
@@ -72,7 +61,6 @@ export function Validate({ missingConfig, userRequest, status, service, onError,
|
|
|
72
61
|
// Build completion message showing which config properties are needed
|
|
73
62
|
const message = getUnresolvedPlaceholdersMessage(withDescriptions.length);
|
|
74
63
|
setCompletionMessage(message);
|
|
75
|
-
setConfigRequirements(withDescriptions);
|
|
76
64
|
// Add validation message to timeline before Config component
|
|
77
65
|
workflowHandlers.addToTimeline(createMessage({ text: message }));
|
|
78
66
|
// Create Config component and add to queue
|
|
@@ -152,13 +140,7 @@ export function Validate({ missingConfig, userRequest, status, service, onError,
|
|
|
152
140
|
lifecycleHandlers,
|
|
153
141
|
workflowHandlers,
|
|
154
142
|
]);
|
|
155
|
-
|
|
156
|
-
error,
|
|
157
|
-
completionMessage,
|
|
158
|
-
configRequirements,
|
|
159
|
-
validated: error === null && completionMessage !== null,
|
|
160
|
-
};
|
|
161
|
-
return _jsx(ValidateView, { state: state, status: status });
|
|
143
|
+
return (_jsx(ValidateView, { status: status, completionMessage: completionMessage, error: error }));
|
|
162
144
|
}
|
|
163
145
|
/**
|
|
164
146
|
* Build prompt for VALIDATE tool
|