prompt-language-shell 0.9.0 → 0.9.4
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} +24 -17
- package/dist/{ui → components}/Component.js +31 -26
- package/dist/{ui → components}/Workflow.js +23 -7
- package/dist/{ui → components/controllers}/Answer.js +18 -17
- package/dist/{ui → components/controllers}/Command.js +21 -24
- package/dist/{ui → components/controllers}/Config.js +17 -119
- package/dist/components/controllers/Confirm.js +42 -0
- package/dist/components/controllers/Execute.js +288 -0
- package/dist/{ui → components/controllers}/Introspect.js +22 -39
- package/dist/components/controllers/Refinement.js +18 -0
- package/dist/{ui → components/controllers}/Schedule.js +8 -124
- package/dist/{ui → components/controllers}/Validate.js +37 -50
- 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/Execute.js +60 -0
- package/dist/{ui → components/views}/Feedback.js +3 -3
- package/dist/components/views/Introspect.js +17 -0
- package/dist/{ui → components/views}/Label.js +3 -3
- package/dist/{ui → components/views}/List.js +3 -3
- 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 +120 -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 +10 -7
- 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/{services/config-labels.js → configuration/labels.js} +1 -1
- package/dist/configuration/schema.js +2 -2
- package/dist/configuration/steps.js +171 -0
- package/dist/configuration/transformation.js +17 -0
- package/dist/execution/handlers.js +20 -60
- package/dist/execution/processing.js +3 -1
- package/dist/execution/reducer.js +34 -44
- package/dist/execution/runner.js +99 -0
- package/dist/execution/types.js +4 -4
- package/dist/execution/utils.js +23 -1
- package/dist/index.js +1 -1
- package/dist/services/components.js +109 -394
- package/dist/services/logger.js +3 -3
- package/dist/services/messages.js +19 -0
- package/dist/services/refinement.js +5 -2
- package/dist/services/router.js +136 -55
- package/dist/services/shell.js +26 -6
- package/dist/services/timing.js +1 -0
- package/dist/skills/execute.md +40 -14
- package/dist/tools/execute.tool.js +0 -4
- package/dist/types/schemas.js +0 -1
- package/package.json +1 -1
- package/dist/parser.js +0 -13
- package/dist/services/config-utils.js +0 -20
- package/dist/ui/Confirm.js +0 -62
- package/dist/ui/Execute.js +0 -294
- package/dist/ui/Refinement.js +0 -23
- package/dist/ui/Task.js +0 -175
- /package/dist/{ui → components/views}/Debug.js +0 -0
- /package/dist/{ui → components/views}/Message.js +0 -0
- /package/dist/{ui → components/views}/Panel.js +0 -0
|
@@ -0,0 +1,288 @@
|
|
|
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';
|
|
17
|
+
const MINIMUM_PROCESSING_TIME = 400;
|
|
18
|
+
/**
|
|
19
|
+
* Create an ExecuteState with defaults
|
|
20
|
+
*/
|
|
21
|
+
function createExecuteState(overrides = {}) {
|
|
22
|
+
return {
|
|
23
|
+
message: '',
|
|
24
|
+
summary: '',
|
|
25
|
+
tasks: [],
|
|
26
|
+
completionMessage: null,
|
|
27
|
+
error: null,
|
|
28
|
+
...overrides,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Execute controller: Runs tasks sequentially and manages all execution state
|
|
33
|
+
*/
|
|
34
|
+
export function Execute({ tasks: inputTasks, status, service, upcoming, label, requestHandlers, lifecycleHandlers, workflowHandlers, }) {
|
|
35
|
+
const isActive = status === ComponentStatus.Active;
|
|
36
|
+
const [localState, dispatch] = useReducer(executeReducer, initialState);
|
|
37
|
+
// Track working directory across commands (persists cd changes)
|
|
38
|
+
const workdirRef = useRef(undefined);
|
|
39
|
+
// Ref to collect live output during execution (dispatched every second)
|
|
40
|
+
const outputRef = useRef({ stdout: '', stderr: '' });
|
|
41
|
+
// Ref to track if current task execution is cancelled
|
|
42
|
+
const cancelledRef = useRef(false);
|
|
43
|
+
const { error, tasks, message, hasProcessed, completionMessage, summary } = localState;
|
|
44
|
+
// Derive current task index from tasks
|
|
45
|
+
const currentTaskIndex = getCurrentTaskIndex(tasks);
|
|
46
|
+
// Derive states
|
|
47
|
+
const isLoading = isActive && tasks.length === 0 && !error && !hasProcessed;
|
|
48
|
+
const isExecuting = isActive && currentTaskIndex < tasks.length;
|
|
49
|
+
const showTasks = !isActive && tasks.length > 0;
|
|
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
|
|
53
|
+
useEffect(() => {
|
|
54
|
+
if (!runningTask?.startTime || !isExecuting)
|
|
55
|
+
return;
|
|
56
|
+
const taskStartTime = runningTask.startTime;
|
|
57
|
+
const interval = setInterval(() => {
|
|
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
|
+
});
|
|
70
|
+
}, ELAPSED_UPDATE_INTERVAL);
|
|
71
|
+
return () => {
|
|
72
|
+
clearInterval(interval);
|
|
73
|
+
};
|
|
74
|
+
}, [runningTask?.startTime, isExecuting, currentTaskIndex]);
|
|
75
|
+
// Handle cancel - state already in reducer, just need to update final output
|
|
76
|
+
const handleCancel = useCallback(() => {
|
|
77
|
+
cancelledRef.current = true;
|
|
78
|
+
dispatch({ type: ExecuteActionType.CancelExecution });
|
|
79
|
+
// Build final state with current output for the running task
|
|
80
|
+
const updatedTasks = tasks.map((task) => {
|
|
81
|
+
if (task.status === ExecutionStatus.Running) {
|
|
82
|
+
return {
|
|
83
|
+
...task,
|
|
84
|
+
status: ExecutionStatus.Aborted,
|
|
85
|
+
output: {
|
|
86
|
+
stdout: outputRef.current.stdout,
|
|
87
|
+
stderr: outputRef.current.stderr,
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
else if (task.status === ExecutionStatus.Pending) {
|
|
92
|
+
return { ...task, status: ExecutionStatus.Cancelled };
|
|
93
|
+
}
|
|
94
|
+
return task;
|
|
95
|
+
});
|
|
96
|
+
const finalState = createExecuteState({
|
|
97
|
+
message,
|
|
98
|
+
summary,
|
|
99
|
+
tasks: updatedTasks,
|
|
100
|
+
});
|
|
101
|
+
requestHandlers.onCompleted(finalState);
|
|
102
|
+
requestHandlers.onAborted('execution');
|
|
103
|
+
}, [message, summary, tasks, requestHandlers]);
|
|
104
|
+
useInput((_, key) => {
|
|
105
|
+
if (key.escape && (isLoading || isExecuting)) {
|
|
106
|
+
handleCancel();
|
|
107
|
+
}
|
|
108
|
+
}, { isActive: (isLoading || isExecuting) && isActive });
|
|
109
|
+
// Process tasks to get commands from AI
|
|
110
|
+
useEffect(() => {
|
|
111
|
+
if (!isActive || tasks.length > 0 || hasProcessed) {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
let mounted = true;
|
|
115
|
+
async function process(svc) {
|
|
116
|
+
const startTime = Date.now();
|
|
117
|
+
try {
|
|
118
|
+
const result = await processTasks(inputTasks, svc);
|
|
119
|
+
await ensureMinimumTime(startTime, MINIMUM_PROCESSING_TIME);
|
|
120
|
+
if (!mounted)
|
|
121
|
+
return;
|
|
122
|
+
// Add debug components to timeline if present
|
|
123
|
+
if (result.debug?.length) {
|
|
124
|
+
workflowHandlers.addToTimeline(...result.debug);
|
|
125
|
+
}
|
|
126
|
+
if (result.commands.length === 0) {
|
|
127
|
+
if (result.error) {
|
|
128
|
+
const errorMessage = getExecutionErrorMessage(result.error);
|
|
129
|
+
workflowHandlers.addToTimeline(createMessage({ text: errorMessage }, ComponentStatus.Done));
|
|
130
|
+
requestHandlers.onCompleted(createExecuteState({ message: result.message }));
|
|
131
|
+
lifecycleHandlers.completeActive();
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
dispatch({
|
|
135
|
+
type: ExecuteActionType.ProcessingComplete,
|
|
136
|
+
payload: { message: result.message },
|
|
137
|
+
});
|
|
138
|
+
requestHandlers.onCompleted(createExecuteState({ message: result.message }));
|
|
139
|
+
lifecycleHandlers.completeActive();
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
// Create task data from commands
|
|
143
|
+
const tasks = result.commands.map((cmd, index) => ({
|
|
144
|
+
label: inputTasks[index]?.action ?? cmd.description,
|
|
145
|
+
command: cmd,
|
|
146
|
+
status: ExecutionStatus.Pending,
|
|
147
|
+
elapsed: 0,
|
|
148
|
+
output: null,
|
|
149
|
+
}));
|
|
150
|
+
dispatch({
|
|
151
|
+
type: ExecuteActionType.CommandsReady,
|
|
152
|
+
payload: {
|
|
153
|
+
message: result.message,
|
|
154
|
+
summary: result.summary,
|
|
155
|
+
tasks,
|
|
156
|
+
},
|
|
157
|
+
});
|
|
158
|
+
requestHandlers.onCompleted(createExecuteState({
|
|
159
|
+
message: result.message,
|
|
160
|
+
summary: result.summary,
|
|
161
|
+
tasks,
|
|
162
|
+
}));
|
|
163
|
+
}
|
|
164
|
+
catch (err) {
|
|
165
|
+
await ensureMinimumTime(startTime, MINIMUM_PROCESSING_TIME);
|
|
166
|
+
if (mounted) {
|
|
167
|
+
const errorMessage = formatErrorMessage(err);
|
|
168
|
+
dispatch({
|
|
169
|
+
type: ExecuteActionType.ProcessingError,
|
|
170
|
+
payload: { error: errorMessage },
|
|
171
|
+
});
|
|
172
|
+
requestHandlers.onCompleted(createExecuteState({ error: errorMessage }));
|
|
173
|
+
requestHandlers.onError(errorMessage);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
void process(service);
|
|
178
|
+
return () => {
|
|
179
|
+
mounted = false;
|
|
180
|
+
};
|
|
181
|
+
}, [
|
|
182
|
+
inputTasks,
|
|
183
|
+
isActive,
|
|
184
|
+
service,
|
|
185
|
+
requestHandlers,
|
|
186
|
+
lifecycleHandlers,
|
|
187
|
+
workflowHandlers,
|
|
188
|
+
tasks.length,
|
|
189
|
+
hasProcessed,
|
|
190
|
+
]);
|
|
191
|
+
// Execute current task
|
|
192
|
+
useEffect(() => {
|
|
193
|
+
if (!isActive ||
|
|
194
|
+
tasks.length === 0 ||
|
|
195
|
+
currentTaskIndex >= tasks.length ||
|
|
196
|
+
error) {
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
const currentTask = tasks[currentTaskIndex];
|
|
200
|
+
if (currentTask.status !== ExecutionStatus.Pending) {
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
cancelledRef.current = false;
|
|
204
|
+
// Mark task as started (running)
|
|
205
|
+
dispatch({
|
|
206
|
+
type: ExecuteActionType.TaskStarted,
|
|
207
|
+
payload: { index: currentTaskIndex, startTime: Date.now() },
|
|
208
|
+
});
|
|
209
|
+
// Reset output ref for new task
|
|
210
|
+
outputRef.current = { stdout: '', stderr: '' };
|
|
211
|
+
// Merge workdir into command
|
|
212
|
+
const command = workdirRef.current
|
|
213
|
+
? { ...currentTask.command, workdir: workdirRef.current }
|
|
214
|
+
: currentTask.command;
|
|
215
|
+
void executeTask(command, currentTaskIndex, {
|
|
216
|
+
onUpdate: (output) => {
|
|
217
|
+
if (!cancelledRef.current) {
|
|
218
|
+
outputRef.current = { stdout: output.stdout, stderr: output.stderr };
|
|
219
|
+
}
|
|
220
|
+
},
|
|
221
|
+
onComplete: (elapsed, execOutput) => {
|
|
222
|
+
if (cancelledRef.current)
|
|
223
|
+
return;
|
|
224
|
+
// Track working directory
|
|
225
|
+
if (execOutput.workdir) {
|
|
226
|
+
workdirRef.current = execOutput.workdir;
|
|
227
|
+
}
|
|
228
|
+
const tasksWithOutput = tasks.map((task, i) => i === currentTaskIndex
|
|
229
|
+
? {
|
|
230
|
+
...task,
|
|
231
|
+
output: {
|
|
232
|
+
stdout: execOutput.stdout,
|
|
233
|
+
stderr: execOutput.stderr,
|
|
234
|
+
},
|
|
235
|
+
}
|
|
236
|
+
: task);
|
|
237
|
+
const result = handleTaskCompletion(currentTaskIndex, elapsed, {
|
|
238
|
+
tasks: tasksWithOutput,
|
|
239
|
+
message,
|
|
240
|
+
summary,
|
|
241
|
+
});
|
|
242
|
+
dispatch(result.action);
|
|
243
|
+
requestHandlers.onCompleted(result.finalState);
|
|
244
|
+
if (result.shouldComplete) {
|
|
245
|
+
lifecycleHandlers.completeActive();
|
|
246
|
+
}
|
|
247
|
+
},
|
|
248
|
+
onError: (errorMsg, execOutput) => {
|
|
249
|
+
if (cancelledRef.current)
|
|
250
|
+
return;
|
|
251
|
+
// Track working directory
|
|
252
|
+
if (execOutput.workdir) {
|
|
253
|
+
workdirRef.current = execOutput.workdir;
|
|
254
|
+
}
|
|
255
|
+
const tasksWithOutput = tasks.map((task, i) => i === currentTaskIndex
|
|
256
|
+
? {
|
|
257
|
+
...task,
|
|
258
|
+
output: {
|
|
259
|
+
stdout: execOutput.stdout,
|
|
260
|
+
stderr: execOutput.stderr,
|
|
261
|
+
},
|
|
262
|
+
error: execOutput.error || undefined,
|
|
263
|
+
}
|
|
264
|
+
: task);
|
|
265
|
+
const result = handleTaskFailure(currentTaskIndex, errorMsg, {
|
|
266
|
+
tasks: tasksWithOutput,
|
|
267
|
+
message,
|
|
268
|
+
summary,
|
|
269
|
+
});
|
|
270
|
+
dispatch(result.action);
|
|
271
|
+
requestHandlers.onCompleted(result.finalState);
|
|
272
|
+
const errorMessage = getExecutionErrorMessage(errorMsg);
|
|
273
|
+
requestHandlers.onError(errorMessage);
|
|
274
|
+
},
|
|
275
|
+
});
|
|
276
|
+
}, [
|
|
277
|
+
isActive,
|
|
278
|
+
tasks,
|
|
279
|
+
currentTaskIndex,
|
|
280
|
+
message,
|
|
281
|
+
summary,
|
|
282
|
+
error,
|
|
283
|
+
requestHandlers,
|
|
284
|
+
lifecycleHandlers,
|
|
285
|
+
workflowHandlers,
|
|
286
|
+
]);
|
|
287
|
+
return (_jsx(ExecuteView, { isLoading: isLoading, isExecuting: isExecuting, isActive: isActive, error: error, message: message, tasks: tasks, completionMessage: completionMessage, showTasks: showTasks, upcoming: upcoming, label: label }));
|
|
288
|
+
}
|
|
@@ -1,24 +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
|
-
|
|
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';
|
|
12
12
|
const MIN_PROCESSING_TIME = 1000;
|
|
13
|
-
export const IntrospectView = ({ state, status, children, }) => {
|
|
14
|
-
const isActive = status === ComponentStatus.Active;
|
|
15
|
-
const { error } = state;
|
|
16
|
-
// Don't render wrapper when done and nothing to show
|
|
17
|
-
if (!isActive && !error && !children) {
|
|
18
|
-
return null;
|
|
19
|
-
}
|
|
20
|
-
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] }));
|
|
21
|
-
};
|
|
22
13
|
/**
|
|
23
14
|
* Introspect controller: Lists capabilities via LLM
|
|
24
15
|
*/
|
|
@@ -26,7 +17,6 @@ export function Introspect({ tasks, status, service, children, debug = DebugLeve
|
|
|
26
17
|
const isActive = status === ComponentStatus.Active;
|
|
27
18
|
const [error, setError] = useState(null);
|
|
28
19
|
const [capabilities, setCapabilities] = useState(null);
|
|
29
|
-
const [message, setMessage] = useState(null);
|
|
30
20
|
useInput((input, key) => {
|
|
31
21
|
if (key.escape && isActive) {
|
|
32
22
|
requestHandlers.onAborted('introspection');
|
|
@@ -51,24 +41,21 @@ export function Introspect({ tasks, status, service, children, debug = DebugLeve
|
|
|
51
41
|
if (result.debug?.length) {
|
|
52
42
|
workflowHandlers.addToTimeline(...result.debug);
|
|
53
43
|
}
|
|
54
|
-
//
|
|
55
|
-
|
|
56
|
-
// Filter out
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
}
|
|
62
|
-
setCapabilities(caps);
|
|
63
|
-
setMessage(result.message);
|
|
44
|
+
// Destructure message from result
|
|
45
|
+
const { message } = result;
|
|
46
|
+
// Filter out meta workflow capabilities when not in debug mode
|
|
47
|
+
const capabilities = debug === DebugLevel.None
|
|
48
|
+
? result.capabilities.filter((cap) => cap.origin !== Origin.Indirect)
|
|
49
|
+
: result.capabilities;
|
|
50
|
+
setCapabilities(capabilities);
|
|
64
51
|
const finalState = {
|
|
65
52
|
error: null,
|
|
66
|
-
capabilities
|
|
67
|
-
message
|
|
53
|
+
capabilities,
|
|
54
|
+
message,
|
|
68
55
|
};
|
|
69
56
|
requestHandlers.onCompleted(finalState);
|
|
70
57
|
// Add Report component to queue
|
|
71
|
-
workflowHandlers.addToQueue(
|
|
58
|
+
workflowHandlers.addToQueue(createReport({ message, capabilities }));
|
|
72
59
|
// Signal completion
|
|
73
60
|
lifecycleHandlers.completeActive();
|
|
74
61
|
}
|
|
@@ -101,10 +88,6 @@ export function Introspect({ tasks, status, service, children, debug = DebugLeve
|
|
|
101
88
|
lifecycleHandlers,
|
|
102
89
|
workflowHandlers,
|
|
103
90
|
]);
|
|
104
|
-
const
|
|
105
|
-
|
|
106
|
-
capabilities: capabilities || [],
|
|
107
|
-
message,
|
|
108
|
-
};
|
|
109
|
-
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 }));
|
|
110
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
|
+
};
|
|
@@ -1,121 +1,11 @@
|
|
|
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
|
-
|
|
9
|
-
import { Label } from './Label.js';
|
|
10
|
-
import { List } from './List.js';
|
|
11
|
-
export function taskToListItem(task, highlightedChildIndex = null, isDefineTaskWithoutSelection = false, status = ComponentStatus.Done, debug = DebugLevel.None) {
|
|
12
|
-
const taskColors = getTaskColors(task.type, status);
|
|
13
|
-
// Determine description color based on status
|
|
14
|
-
let descriptionColor = taskColors.description;
|
|
15
|
-
if (status === ComponentStatus.Pending) {
|
|
16
|
-
descriptionColor = Palette.SoftWhite;
|
|
17
|
-
}
|
|
18
|
-
const item = {
|
|
19
|
-
description: {
|
|
20
|
-
text: task.action,
|
|
21
|
-
color: descriptionColor,
|
|
22
|
-
},
|
|
23
|
-
type: { text: getTaskTypeLabel(task.type, debug), color: taskColors.type },
|
|
24
|
-
children: [],
|
|
25
|
-
};
|
|
26
|
-
// Mark define tasks with right arrow when no selection has been made
|
|
27
|
-
if (isDefineTaskWithoutSelection) {
|
|
28
|
-
item.marker = ' → ';
|
|
29
|
-
item.markerColor = getTaskColors(TaskType.Schedule, status).type;
|
|
30
|
-
}
|
|
31
|
-
// Add children for Define tasks with options
|
|
32
|
-
if (task.type === TaskType.Define && Array.isArray(task.params?.options)) {
|
|
33
|
-
item.children = task.params.options.map((option, index) => {
|
|
34
|
-
// Determine the type based on selection state
|
|
35
|
-
let childType = TaskType.Select;
|
|
36
|
-
if (highlightedChildIndex !== null) {
|
|
37
|
-
// A selection was made - mark others as discarded
|
|
38
|
-
childType =
|
|
39
|
-
index === highlightedChildIndex ? TaskType.Execute : TaskType.Discard;
|
|
40
|
-
}
|
|
41
|
-
const colors = getTaskColors(childType, status);
|
|
42
|
-
const planColors = getTaskColors(TaskType.Schedule, status);
|
|
43
|
-
return {
|
|
44
|
-
description: {
|
|
45
|
-
text: option,
|
|
46
|
-
color: colors.description,
|
|
47
|
-
highlightedColor: planColors.description,
|
|
48
|
-
},
|
|
49
|
-
type: {
|
|
50
|
-
text: getTaskTypeLabel(childType, debug),
|
|
51
|
-
color: colors.type,
|
|
52
|
-
highlightedColor: planColors.type,
|
|
53
|
-
},
|
|
54
|
-
};
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
// Add children for Group tasks with subtasks
|
|
58
|
-
const scheduledTask = task;
|
|
59
|
-
if (task.type === TaskType.Group &&
|
|
60
|
-
scheduledTask.subtasks &&
|
|
61
|
-
Array.isArray(scheduledTask.subtasks) &&
|
|
62
|
-
scheduledTask.subtasks.length > 0) {
|
|
63
|
-
item.children = scheduledTask.subtasks.map((subtask) => {
|
|
64
|
-
const subtaskColors = getTaskColors(subtask.type, status);
|
|
65
|
-
return {
|
|
66
|
-
description: {
|
|
67
|
-
text: subtask.action,
|
|
68
|
-
color: Palette.AshGray,
|
|
69
|
-
},
|
|
70
|
-
type: {
|
|
71
|
-
text: getTaskTypeLabel(subtask.type, debug),
|
|
72
|
-
color: subtaskColors.type,
|
|
73
|
-
},
|
|
74
|
-
};
|
|
75
|
-
});
|
|
76
|
-
}
|
|
77
|
-
return item;
|
|
78
|
-
}
|
|
79
|
-
export const ScheduleView = ({ message, tasks, state, status, debug = DebugLevel.None, }) => {
|
|
80
|
-
const isActive = status === ComponentStatus.Active;
|
|
81
|
-
const { highlightedIndex, currentDefineGroupIndex, completedSelections } = state;
|
|
82
|
-
// Find all Define tasks
|
|
83
|
-
const defineTaskIndices = tasks
|
|
84
|
-
.map((t, idx) => (t.type === TaskType.Define ? idx : -1))
|
|
85
|
-
.filter((idx) => idx !== -1);
|
|
86
|
-
// Get the current active define task
|
|
87
|
-
const currentDefineTaskIndex = defineTaskIndices[currentDefineGroupIndex] ?? -1;
|
|
88
|
-
const listItems = tasks.map((task, idx) => {
|
|
89
|
-
// Find which define group this task belongs to (if any)
|
|
90
|
-
const defineGroupIndex = defineTaskIndices.indexOf(idx);
|
|
91
|
-
const isDefineTask = defineGroupIndex !== -1;
|
|
92
|
-
// Determine child selection state
|
|
93
|
-
let childIndex = null;
|
|
94
|
-
if (isDefineTask) {
|
|
95
|
-
if (defineGroupIndex < currentDefineGroupIndex) {
|
|
96
|
-
// Previously completed group - show the selection
|
|
97
|
-
childIndex = completedSelections[defineGroupIndex] ?? null;
|
|
98
|
-
}
|
|
99
|
-
else if (defineGroupIndex === currentDefineGroupIndex) {
|
|
100
|
-
// Current active group - show live navigation unless not active
|
|
101
|
-
if (!isActive) {
|
|
102
|
-
// If not active, show the completed selection for this group too
|
|
103
|
-
childIndex = completedSelections[defineGroupIndex] ?? null;
|
|
104
|
-
}
|
|
105
|
-
else {
|
|
106
|
-
childIndex = null;
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
// Show arrow on current active define task when no child is highlighted and is active
|
|
111
|
-
const isDefineWithoutSelection = isDefineTask &&
|
|
112
|
-
defineGroupIndex === currentDefineGroupIndex &&
|
|
113
|
-
highlightedIndex === null &&
|
|
114
|
-
isActive;
|
|
115
|
-
return taskToListItem(task, childIndex, isDefineWithoutSelection, status, debug);
|
|
116
|
-
});
|
|
117
|
-
return (_jsxs(Box, { flexDirection: "column", children: [message && (_jsx(Box, { marginBottom: 1, marginLeft: 1, children: _jsx(Label, { description: message, taskType: TaskType.Schedule, showType: debug !== DebugLevel.None, status: status, debug: debug }) })), _jsx(Box, { marginLeft: 1, children: _jsx(List, { items: listItems, highlightedIndex: currentDefineTaskIndex >= 0 ? highlightedIndex : null, highlightedParentIndex: currentDefineTaskIndex, showType: debug !== DebugLevel.None }) })] }));
|
|
118
|
-
};
|
|
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';
|
|
119
9
|
/**
|
|
120
10
|
* Schedule controller: Manages task selection and navigation
|
|
121
11
|
*/
|
|
@@ -245,11 +135,5 @@ export function Schedule({ message, tasks, status, debug = DebugLevel.None, requ
|
|
|
245
135
|
}
|
|
246
136
|
}
|
|
247
137
|
}, { isActive: isActive && defineTask !== null });
|
|
248
|
-
|
|
249
|
-
const state = {
|
|
250
|
-
highlightedIndex,
|
|
251
|
-
currentDefineGroupIndex,
|
|
252
|
-
completedSelections,
|
|
253
|
-
};
|
|
254
|
-
return (_jsx(ScheduleView, { message: message, tasks: tasks, state: state, status: status, debug: debug }));
|
|
138
|
+
return (_jsx(ScheduleView, { status: status, message: message, tasks: tasks, highlightedIndex: highlightedIndex, currentDefineGroupIndex: currentDefineGroupIndex, completedSelections: completedSelections, debug: debug }));
|
|
255
139
|
}
|
|
@@ -1,27 +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 { unflattenConfig } from '
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
|
|
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';
|
|
15
15
|
const MIN_PROCESSING_TIME = 1000;
|
|
16
|
-
export const ValidateView = ({ state, status }) => {
|
|
17
|
-
const isActive = status === ComponentStatus.Active;
|
|
18
|
-
const { error, completionMessage } = state;
|
|
19
|
-
// Don't render when not active and nothing to show
|
|
20
|
-
if (!isActive && !completionMessage && !error) {
|
|
21
|
-
return null;
|
|
22
|
-
}
|
|
23
|
-
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] }) }))] }));
|
|
24
|
-
};
|
|
25
16
|
/**
|
|
26
17
|
* Validate controller: Validates missing config
|
|
27
18
|
*/
|
|
@@ -29,7 +20,6 @@ export function Validate({ missingConfig, userRequest, status, service, onError,
|
|
|
29
20
|
const isActive = status === ComponentStatus.Active;
|
|
30
21
|
const [error, setError] = useState(null);
|
|
31
22
|
const [completionMessage, setCompletionMessage] = useState(null);
|
|
32
|
-
const [configRequirements, setConfigRequirements] = useState([]);
|
|
33
23
|
useInput((_, key) => {
|
|
34
24
|
if (key.escape && isActive) {
|
|
35
25
|
onAborted('validation');
|
|
@@ -71,30 +61,33 @@ export function Validate({ missingConfig, userRequest, status, service, onError,
|
|
|
71
61
|
// Build completion message showing which config properties are needed
|
|
72
62
|
const message = getUnresolvedPlaceholdersMessage(withDescriptions.length);
|
|
73
63
|
setCompletionMessage(message);
|
|
74
|
-
setConfigRequirements(withDescriptions);
|
|
75
64
|
// Add validation message to timeline before Config component
|
|
76
|
-
workflowHandlers.addToTimeline(createMessage(message));
|
|
65
|
+
workflowHandlers.addToTimeline(createMessage({ text: message }));
|
|
77
66
|
// Create Config component and add to queue
|
|
78
67
|
const keys = withDescriptions.map((req) => req.path);
|
|
79
|
-
const configDef =
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
68
|
+
const configDef = createConfig({
|
|
69
|
+
steps: createConfigStepsFromSchema(keys),
|
|
70
|
+
onFinished: (config) => {
|
|
71
|
+
// Convert flat dotted keys to nested structure grouped by section
|
|
72
|
+
const configBySection = unflattenConfig(config);
|
|
73
|
+
// Extract and save labels to cache
|
|
74
|
+
const labels = {};
|
|
75
|
+
for (const req of withDescriptions) {
|
|
76
|
+
if (req.description) {
|
|
77
|
+
labels[req.path] = req.description;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
saveConfigLabels(labels);
|
|
81
|
+
// Save each section
|
|
82
|
+
for (const [section, sectionConfig] of Object.entries(configBySection)) {
|
|
83
|
+
saveConfig(section, sectionConfig);
|
|
87
84
|
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
}
|
|
94
|
-
// After config is saved, invoke callback to add Execute component to queue
|
|
95
|
-
onValidationComplete(withDescriptions);
|
|
96
|
-
}, (operation) => {
|
|
97
|
-
onAborted(operation);
|
|
85
|
+
// After config is saved, invoke callback to add Execute component to queue
|
|
86
|
+
onValidationComplete(withDescriptions);
|
|
87
|
+
},
|
|
88
|
+
onAborted: (operation) => {
|
|
89
|
+
onAborted(operation);
|
|
90
|
+
},
|
|
98
91
|
});
|
|
99
92
|
// Override descriptions with LLM-generated ones
|
|
100
93
|
if ('props' in configDef && 'steps' in configDef.props) {
|
|
@@ -147,13 +140,7 @@ export function Validate({ missingConfig, userRequest, status, service, onError,
|
|
|
147
140
|
lifecycleHandlers,
|
|
148
141
|
workflowHandlers,
|
|
149
142
|
]);
|
|
150
|
-
|
|
151
|
-
error,
|
|
152
|
-
completionMessage,
|
|
153
|
-
configRequirements,
|
|
154
|
-
validated: error === null && completionMessage !== null,
|
|
155
|
-
};
|
|
156
|
-
return _jsx(ValidateView, { state: state, status: status });
|
|
143
|
+
return (_jsx(ValidateView, { status: status, completionMessage: completionMessage, error: error }));
|
|
157
144
|
}
|
|
158
145
|
/**
|
|
159
146
|
* Build prompt for VALIDATE tool
|