prompt-language-shell 0.7.8 → 0.8.2
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/anthropic.js +29 -3
- package/dist/services/colors.js +35 -9
- package/dist/services/components.js +28 -7
- package/dist/services/config-labels.js +75 -0
- package/dist/services/config-utils.js +20 -0
- package/dist/services/configuration.js +15 -36
- package/dist/services/registry.js +1 -1
- package/dist/services/router.js +6 -6
- package/dist/services/shell.js +1 -0
- package/dist/services/skills.js +3 -3
- package/dist/skills/introspect.md +52 -43
- package/dist/skills/schedule.md +8 -3
- package/dist/tools/introspect.tool.js +18 -9
- package/dist/types/guards.js +25 -0
- package/dist/types/types.js +6 -0
- package/dist/ui/Answer.js +7 -7
- package/dist/ui/Command.js +12 -11
- package/dist/ui/Component.js +2 -2
- package/dist/ui/Config.js +66 -26
- package/dist/ui/Confirm.js +6 -6
- package/dist/ui/Execute.js +124 -36
- package/dist/ui/Feedback.js +1 -1
- package/dist/ui/Introspect.js +5 -52
- package/dist/ui/Label.js +1 -1
- package/dist/ui/List.js +2 -1
- package/dist/ui/Main.js +1 -1
- package/dist/ui/Report.js +4 -8
- package/dist/ui/Schedule.js +5 -5
- package/dist/ui/Spinner.js +5 -2
- package/dist/ui/Subtask.js +14 -3
- package/dist/ui/Task.js +19 -14
- package/dist/ui/Validate.js +42 -31
- package/dist/ui/Workflow.js +1 -1
- package/package.json +12 -12
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
|
|
@@ -38,10 +69,6 @@ export function Execute({ tasks, state, status, service, handlers, }) {
|
|
|
38
69
|
if (!isActive || taskInfos.length > 0 || hasProcessed) {
|
|
39
70
|
return;
|
|
40
71
|
}
|
|
41
|
-
if (!service) {
|
|
42
|
-
setError('No service available');
|
|
43
|
-
return;
|
|
44
|
-
}
|
|
45
72
|
let mounted = true;
|
|
46
73
|
async function process(svc) {
|
|
47
74
|
const startTime = Date.now();
|
|
@@ -69,7 +96,12 @@ export function Execute({ tasks, state, status, service, handlers, }) {
|
|
|
69
96
|
setHasProcessed(true);
|
|
70
97
|
handlers?.updateState({
|
|
71
98
|
message: result.message,
|
|
99
|
+
summary: '',
|
|
72
100
|
taskInfos: [],
|
|
101
|
+
completed: 0,
|
|
102
|
+
taskExecutionTimes: [],
|
|
103
|
+
completionMessage: null,
|
|
104
|
+
error: null,
|
|
73
105
|
});
|
|
74
106
|
handlers?.completeActive();
|
|
75
107
|
return;
|
|
@@ -80,14 +112,26 @@ export function Execute({ tasks, state, status, service, handlers, }) {
|
|
|
80
112
|
command: replacePlaceholders(cmd.command, userConfig),
|
|
81
113
|
}));
|
|
82
114
|
// Set message, summary, and create task infos
|
|
83
|
-
|
|
84
|
-
|
|
115
|
+
const newMessage = result.message;
|
|
116
|
+
const newSummary = result.summary || '';
|
|
85
117
|
const infos = resolvedCommands.map((cmd, index) => ({
|
|
86
118
|
label: tasks[index]?.action,
|
|
87
119
|
command: cmd,
|
|
88
120
|
}));
|
|
121
|
+
setMessage(newMessage);
|
|
122
|
+
setSummary(newSummary);
|
|
89
123
|
setTaskInfos(infos);
|
|
90
|
-
|
|
124
|
+
setCompleted(0); // Start with first task
|
|
125
|
+
// Update state after AI processing
|
|
126
|
+
handlers?.updateState({
|
|
127
|
+
message: newMessage,
|
|
128
|
+
summary: newSummary,
|
|
129
|
+
taskInfos: infos,
|
|
130
|
+
completed: 0,
|
|
131
|
+
taskExecutionTimes: [],
|
|
132
|
+
completionMessage: null,
|
|
133
|
+
error: null,
|
|
134
|
+
});
|
|
91
135
|
}
|
|
92
136
|
catch (err) {
|
|
93
137
|
await ensureMinimumTime(startTime, MINIMUM_PROCESSING_TIME);
|
|
@@ -95,12 +139,20 @@ export function Execute({ tasks, state, status, service, handlers, }) {
|
|
|
95
139
|
const errorMessage = formatErrorMessage(err);
|
|
96
140
|
setError(errorMessage);
|
|
97
141
|
setHasProcessed(true);
|
|
98
|
-
handlers?.updateState({
|
|
142
|
+
handlers?.updateState({
|
|
143
|
+
message: '',
|
|
144
|
+
summary: '',
|
|
145
|
+
taskInfos: [],
|
|
146
|
+
completed: 0,
|
|
147
|
+
taskExecutionTimes: [],
|
|
148
|
+
completionMessage: null,
|
|
149
|
+
error: errorMessage,
|
|
150
|
+
});
|
|
99
151
|
handlers?.onError(errorMessage);
|
|
100
152
|
}
|
|
101
153
|
}
|
|
102
154
|
}
|
|
103
|
-
process(service);
|
|
155
|
+
void process(service);
|
|
104
156
|
return () => {
|
|
105
157
|
mounted = false;
|
|
106
158
|
};
|
|
@@ -109,62 +161,94 @@ export function Execute({ tasks, state, status, service, handlers, }) {
|
|
|
109
161
|
const handleTaskComplete = useCallback((index, _output, elapsed) => {
|
|
110
162
|
const updatedTimes = [...taskExecutionTimes, elapsed];
|
|
111
163
|
setTaskExecutionTimes(updatedTimes);
|
|
164
|
+
// Update task with elapsed time and success status
|
|
165
|
+
const updatedTaskInfos = taskInfos.map((task, i) => i === index
|
|
166
|
+
? { ...task, status: ExecutionStatus.Success, elapsed }
|
|
167
|
+
: task);
|
|
168
|
+
setTaskInfos(updatedTaskInfos);
|
|
112
169
|
if (index < taskInfos.length - 1) {
|
|
113
170
|
// More tasks to execute
|
|
114
|
-
|
|
171
|
+
setCompleted(index + 1);
|
|
172
|
+
handlers?.updateState({
|
|
173
|
+
message,
|
|
174
|
+
summary,
|
|
175
|
+
taskInfos: updatedTaskInfos,
|
|
176
|
+
completed: index + 1,
|
|
177
|
+
taskExecutionTimes: updatedTimes,
|
|
178
|
+
completionMessage: null,
|
|
179
|
+
error: null,
|
|
180
|
+
});
|
|
115
181
|
}
|
|
116
182
|
else {
|
|
117
183
|
// All tasks complete
|
|
118
|
-
setActiveTaskIndex(-1);
|
|
119
184
|
const totalElapsed = updatedTimes.reduce((sum, time) => sum + time, 0);
|
|
120
|
-
const summaryText = summary
|
|
185
|
+
const summaryText = summary.trim() || 'Execution completed';
|
|
121
186
|
const completion = `${summaryText} in ${formatDuration(totalElapsed)}.`;
|
|
122
187
|
setCompletionMessage(completion);
|
|
123
188
|
handlers?.updateState({
|
|
124
189
|
message,
|
|
125
190
|
summary,
|
|
126
|
-
taskInfos,
|
|
127
|
-
|
|
191
|
+
taskInfos: updatedTaskInfos,
|
|
192
|
+
completed: index + 1,
|
|
128
193
|
taskExecutionTimes: updatedTimes,
|
|
129
194
|
completionMessage: completion,
|
|
195
|
+
error: null,
|
|
130
196
|
});
|
|
131
197
|
handlers?.completeActive();
|
|
132
198
|
}
|
|
133
199
|
}, [taskInfos, message, handlers, taskExecutionTimes, summary]);
|
|
134
|
-
const handleTaskError = useCallback((index, error) => {
|
|
200
|
+
const handleTaskError = useCallback((index, error, elapsed) => {
|
|
135
201
|
const task = taskInfos[index];
|
|
136
|
-
const isCritical = task
|
|
202
|
+
const isCritical = task.command.critical !== false; // Default to true
|
|
203
|
+
// Update task with elapsed time and failed status
|
|
204
|
+
const updatedTaskInfos = taskInfos.map((task, i) => i === index
|
|
205
|
+
? { ...task, status: ExecutionStatus.Failed, elapsed }
|
|
206
|
+
: task);
|
|
207
|
+
setTaskInfos(updatedTaskInfos);
|
|
137
208
|
if (isCritical) {
|
|
138
209
|
// Critical failure - stop execution
|
|
139
|
-
setActiveTaskIndex(-1);
|
|
140
210
|
setError(error);
|
|
141
211
|
handlers?.updateState({
|
|
142
212
|
message,
|
|
143
|
-
|
|
144
|
-
|
|
213
|
+
summary,
|
|
214
|
+
taskInfos: updatedTaskInfos,
|
|
215
|
+
completed: index + 1,
|
|
216
|
+
taskExecutionTimes,
|
|
217
|
+
completionMessage: null,
|
|
145
218
|
error,
|
|
146
219
|
});
|
|
147
220
|
handlers?.onError(error);
|
|
148
221
|
}
|
|
149
222
|
else {
|
|
150
223
|
// Non-critical failure - continue to next task
|
|
224
|
+
const updatedTimes = [...taskExecutionTimes, elapsed];
|
|
225
|
+
setTaskExecutionTimes(updatedTimes);
|
|
151
226
|
if (index < taskInfos.length - 1) {
|
|
152
|
-
|
|
227
|
+
setCompleted(index + 1);
|
|
228
|
+
handlers?.updateState({
|
|
229
|
+
message,
|
|
230
|
+
summary,
|
|
231
|
+
taskInfos: updatedTaskInfos,
|
|
232
|
+
completed: index + 1,
|
|
233
|
+
taskExecutionTimes: updatedTimes,
|
|
234
|
+
completionMessage: null,
|
|
235
|
+
error: null,
|
|
236
|
+
});
|
|
153
237
|
}
|
|
154
238
|
else {
|
|
155
239
|
// Last task, complete execution
|
|
156
|
-
|
|
157
|
-
const
|
|
158
|
-
const summaryText = summary?.trim() || 'Execution completed';
|
|
240
|
+
const totalElapsed = updatedTimes.reduce((sum, time) => sum + time, 0);
|
|
241
|
+
const summaryText = summary.trim() || 'Execution completed';
|
|
159
242
|
const completion = `${summaryText} in ${formatDuration(totalElapsed)}.`;
|
|
160
243
|
setCompletionMessage(completion);
|
|
161
244
|
handlers?.updateState({
|
|
162
245
|
message,
|
|
163
246
|
summary,
|
|
164
|
-
taskInfos,
|
|
165
|
-
|
|
166
|
-
taskExecutionTimes,
|
|
247
|
+
taskInfos: updatedTaskInfos,
|
|
248
|
+
completed: index + 1,
|
|
249
|
+
taskExecutionTimes: updatedTimes,
|
|
167
250
|
completionMessage: completion,
|
|
251
|
+
error: null,
|
|
168
252
|
});
|
|
169
253
|
handlers?.completeActive();
|
|
170
254
|
}
|
|
@@ -175,15 +259,19 @@ export function Execute({ tasks, state, status, service, handlers, }) {
|
|
|
175
259
|
// Just update state, don't call onAborted (already called at Execute level)
|
|
176
260
|
handlers?.updateState({
|
|
177
261
|
message,
|
|
262
|
+
summary,
|
|
178
263
|
taskInfos,
|
|
179
|
-
|
|
264
|
+
completed,
|
|
265
|
+
taskExecutionTimes,
|
|
266
|
+
completionMessage: null,
|
|
267
|
+
error: null,
|
|
180
268
|
});
|
|
181
|
-
}, [taskInfos, message, handlers]);
|
|
269
|
+
}, [taskInfos, message, summary, completed, taskExecutionTimes, handlers]);
|
|
182
270
|
// Return null only when loading completes with no commands
|
|
183
271
|
if (!isActive && taskInfos.length === 0 && !error) {
|
|
184
272
|
return null;
|
|
185
273
|
}
|
|
186
274
|
// Show completed steps when not active
|
|
187
275
|
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 ===
|
|
276
|
+
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
277
|
}
|
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/Introspect.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useEffect, useState } from 'react';
|
|
3
3
|
import { Box, Text } from 'ink';
|
|
4
|
-
import { ComponentStatus
|
|
4
|
+
import { ComponentStatus } from '../types/components.js';
|
|
5
5
|
import { Colors, getTextColor } from '../services/colors.js';
|
|
6
6
|
import { addDebugToTimeline, createReportDefinition, } from '../services/components.js';
|
|
7
7
|
import { DebugLevel } from '../services/configuration.js';
|
|
@@ -10,49 +10,7 @@ import { formatErrorMessage } from '../services/messages.js';
|
|
|
10
10
|
import { ensureMinimumTime } from '../services/timing.js';
|
|
11
11
|
import { Spinner } from './Spinner.js';
|
|
12
12
|
const MIN_PROCESSING_TIME = 1000;
|
|
13
|
-
|
|
14
|
-
'CONFIGURE',
|
|
15
|
-
'SCHEDULE',
|
|
16
|
-
'INTROSPECT',
|
|
17
|
-
'ANSWER',
|
|
18
|
-
'EXECUTE',
|
|
19
|
-
'VALIDATE',
|
|
20
|
-
'REPORT',
|
|
21
|
-
]);
|
|
22
|
-
const INDIRECT_CAPABILITIES = new Set(['SCHEDULE', 'VALIDATE', 'REPORT']);
|
|
23
|
-
function parseCapabilityFromTask(task) {
|
|
24
|
-
// Parse "NAME: Description" format from task.action
|
|
25
|
-
const colonIndex = task.action.indexOf(':');
|
|
26
|
-
if (colonIndex === -1) {
|
|
27
|
-
const upperName = task.action.toUpperCase();
|
|
28
|
-
// Check for status markers
|
|
29
|
-
const isIncomplete = task.action.includes('(INCOMPLETE)');
|
|
30
|
-
const cleanName = task.action.replace(/\s*\(INCOMPLETE\)\s*/gi, '').trim();
|
|
31
|
-
return {
|
|
32
|
-
name: cleanName,
|
|
33
|
-
description: '',
|
|
34
|
-
isBuiltIn: BUILT_IN_CAPABILITIES.has(upperName),
|
|
35
|
-
isIndirect: INDIRECT_CAPABILITIES.has(upperName),
|
|
36
|
-
isIncomplete,
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
const name = task.action.substring(0, colonIndex).trim();
|
|
40
|
-
const description = task.action.substring(colonIndex + 1).trim();
|
|
41
|
-
// Check for status markers
|
|
42
|
-
const isIncomplete = name.includes('(INCOMPLETE)');
|
|
43
|
-
const cleanName = name.replace(/\s*\(INCOMPLETE\)\s*/gi, '').trim();
|
|
44
|
-
const upperName = cleanName.toUpperCase();
|
|
45
|
-
const isBuiltIn = BUILT_IN_CAPABILITIES.has(upperName);
|
|
46
|
-
const isIndirect = INDIRECT_CAPABILITIES.has(upperName);
|
|
47
|
-
return {
|
|
48
|
-
name: cleanName,
|
|
49
|
-
description,
|
|
50
|
-
isBuiltIn,
|
|
51
|
-
isIndirect,
|
|
52
|
-
isIncomplete,
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
export function Introspect({ tasks, state, status, service, children, debug = DebugLevel.None, handlers, }) {
|
|
13
|
+
export function Introspect({ tasks, state: _state, status, service, children, debug = DebugLevel.None, handlers, }) {
|
|
56
14
|
const isActive = status === ComponentStatus.Active;
|
|
57
15
|
// isActive passed as prop
|
|
58
16
|
const [error, setError] = useState(null);
|
|
@@ -66,11 +24,6 @@ export function Introspect({ tasks, state, status, service, children, debug = De
|
|
|
66
24
|
if (!isActive) {
|
|
67
25
|
return;
|
|
68
26
|
}
|
|
69
|
-
// Skip processing if no service available
|
|
70
|
-
if (!service) {
|
|
71
|
-
setError('No service available');
|
|
72
|
-
return;
|
|
73
|
-
}
|
|
74
27
|
let mounted = true;
|
|
75
28
|
async function process(svc) {
|
|
76
29
|
const startTime = Date.now();
|
|
@@ -83,8 +36,8 @@ export function Introspect({ tasks, state, status, service, children, debug = De
|
|
|
83
36
|
if (mounted) {
|
|
84
37
|
// Add debug components to timeline if present
|
|
85
38
|
addDebugToTimeline(result.debug, handlers);
|
|
86
|
-
//
|
|
87
|
-
let capabilities = result.
|
|
39
|
+
// Capabilities come directly from result - no parsing needed
|
|
40
|
+
let capabilities = result.capabilities;
|
|
88
41
|
// Filter out internal capabilities when not in debug mode
|
|
89
42
|
if (debug === DebugLevel.None) {
|
|
90
43
|
capabilities = capabilities.filter((cap) => cap.name.toUpperCase() !== 'SCHEDULE' &&
|
|
@@ -115,7 +68,7 @@ export function Introspect({ tasks, state, status, service, children, debug = De
|
|
|
115
68
|
}
|
|
116
69
|
}
|
|
117
70
|
}
|
|
118
|
-
process(service);
|
|
71
|
+
void process(service);
|
|
119
72
|
return () => {
|
|
120
73
|
mounted = false;
|
|
121
74
|
};
|
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/Main.js
CHANGED
package/dist/ui/Report.js
CHANGED
|
@@ -1,14 +1,10 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Box, Text } from 'ink';
|
|
3
|
-
import { Colors } from '../services/colors.js';
|
|
4
|
-
function CapabilityItem({ name, description,
|
|
5
|
-
const color =
|
|
6
|
-
? Colors.Origin.Indirect
|
|
7
|
-
: isBuiltIn
|
|
8
|
-
? Colors.Origin.BuiltIn
|
|
9
|
-
: Colors.Origin.UserProvided;
|
|
3
|
+
import { Colors, getOriginColor } from '../services/colors.js';
|
|
4
|
+
function CapabilityItem({ name, description, origin, isIncomplete, }) {
|
|
5
|
+
const color = getOriginColor(origin);
|
|
10
6
|
return (_jsxs(Box, { children: [_jsx(Text, { children: "- " }), _jsx(Text, { color: color, children: name }), _jsxs(Text, { children: [" - ", description] }), isIncomplete && _jsx(Text, { color: Colors.Status.Warning, children: " (incomplete)" })] }));
|
|
11
7
|
}
|
|
12
8
|
export function Report({ message, capabilities }) {
|
|
13
|
-
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { marginLeft: 1, children: _jsx(Text, { children: message }) }), _jsx(Box, { flexDirection: "column", marginLeft: 3, marginTop: 1, children: capabilities.map((capability, index) => (_jsx(CapabilityItem, { name: capability.name, description: capability.description,
|
|
9
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { marginLeft: 1, children: _jsx(Text, { children: message }) }), _jsx(Box, { flexDirection: "column", marginLeft: 3, marginTop: 1, children: capabilities.map((capability, index) => (_jsx(CapabilityItem, { name: capability.name, description: capability.description, origin: capability.origin, isIncomplete: capability.isIncomplete }, index))) })] }));
|
|
14
10
|
}
|
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';
|
|
@@ -37,7 +37,7 @@ function taskToListItem(task, highlightedChildIndex = null, isDefineTaskWithoutS
|
|
|
37
37
|
const planColors = getTaskColors(TaskType.Schedule, isCurrent);
|
|
38
38
|
return {
|
|
39
39
|
description: {
|
|
40
|
-
text:
|
|
40
|
+
text: option,
|
|
41
41
|
color: colors.description,
|
|
42
42
|
highlightedColor: planColors.description,
|
|
43
43
|
},
|
|
@@ -96,7 +96,7 @@ export function Schedule({ message, tasks, state, status, debug = DebugLevel.Non
|
|
|
96
96
|
// Complete the selection phase - it goes to timeline
|
|
97
97
|
// Callback will create a new Plan showing refined tasks (pending) + Confirm (active)
|
|
98
98
|
handlers?.completeActive();
|
|
99
|
-
onSelectionConfirmed(concreteTasks);
|
|
99
|
+
void onSelectionConfirmed(concreteTasks);
|
|
100
100
|
}
|
|
101
101
|
}, [
|
|
102
102
|
isActive,
|
|
@@ -153,7 +153,7 @@ export function Schedule({ message, tasks, state, status, debug = DebugLevel.Non
|
|
|
153
153
|
// This is a Define task - only include the selected option
|
|
154
154
|
const options = task.params.options;
|
|
155
155
|
const selectedIndex = newCompletedSelections[defineGroupIndex];
|
|
156
|
-
const selectedOption =
|
|
156
|
+
const selectedOption = options[selectedIndex];
|
|
157
157
|
// Use Execute as default - LLM will properly classify during refinement
|
|
158
158
|
refinedTasks.push({
|
|
159
159
|
action: selectedOption,
|
|
@@ -171,7 +171,7 @@ export function Schedule({ message, tasks, state, status, debug = DebugLevel.Non
|
|
|
171
171
|
// Complete the selection phase - it goes to timeline
|
|
172
172
|
// Callback will create a new Plan showing refined tasks (pending) + Confirm (active)
|
|
173
173
|
handlers?.completeActive();
|
|
174
|
-
onSelectionConfirmed(refinedTasks);
|
|
174
|
+
void onSelectionConfirmed(refinedTasks);
|
|
175
175
|
}
|
|
176
176
|
else {
|
|
177
177
|
// No selection callback, just complete normally
|
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;
|
|
@@ -16,7 +17,9 @@ export function Spinner() {
|
|
|
16
17
|
return next !== prev ? next : prev;
|
|
17
18
|
});
|
|
18
19
|
}, INTERVAL);
|
|
19
|
-
return () =>
|
|
20
|
+
return () => {
|
|
21
|
+
clearInterval(timer);
|
|
22
|
+
};
|
|
20
23
|
}, []);
|
|
21
|
-
return _jsx(Text, { color:
|
|
24
|
+
return _jsx(Text, { color: Palette.Cyan, children: FRAMES[frame] });
|
|
22
25
|
}
|
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: _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
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { useEffect, useState } from 'react';
|
|
3
|
-
import { ExecutionStatus, executeCommand, } from '../services/shell.js';
|
|
3
|
+
import { ExecutionResult, 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(() => {
|
|
@@ -19,11 +19,16 @@ export function Task({ label, command, isActive, index, onComplete, onAbort, onE
|
|
|
19
19
|
return next !== prev ? next : prev;
|
|
20
20
|
});
|
|
21
21
|
}, 1000);
|
|
22
|
-
return () =>
|
|
22
|
+
return () => {
|
|
23
|
+
clearInterval(interval);
|
|
24
|
+
};
|
|
23
25
|
}, [status, startTime]);
|
|
24
26
|
// Execute command when becoming active
|
|
25
27
|
useEffect(() => {
|
|
26
|
-
if
|
|
28
|
+
// Don't execute if task is cancelled or if not active
|
|
29
|
+
if (!isActive ||
|
|
30
|
+
status === ExecutionStatus.Cancelled ||
|
|
31
|
+
status !== ExecutionStatus.Pending) {
|
|
27
32
|
return;
|
|
28
33
|
}
|
|
29
34
|
let mounted = true;
|
|
@@ -40,14 +45,14 @@ export function Task({ label, command, isActive, index, onComplete, onAbort, onE
|
|
|
40
45
|
setEndTime(end);
|
|
41
46
|
const taskDuration = calculateElapsed(start);
|
|
42
47
|
setElapsed(taskDuration);
|
|
43
|
-
setStatus(output.result ===
|
|
48
|
+
setStatus(output.result === ExecutionResult.Success
|
|
44
49
|
? ExecutionStatus.Success
|
|
45
50
|
: ExecutionStatus.Failed);
|
|
46
|
-
if (output.result ===
|
|
51
|
+
if (output.result === ExecutionResult.Success) {
|
|
47
52
|
onComplete?.(index, output, taskDuration);
|
|
48
53
|
}
|
|
49
54
|
else {
|
|
50
|
-
onError?.(index, output.errors || 'Command failed');
|
|
55
|
+
onError?.(index, output.errors || 'Command failed', taskDuration);
|
|
51
56
|
}
|
|
52
57
|
}
|
|
53
58
|
catch (err) {
|
|
@@ -55,16 +60,16 @@ export function Task({ label, command, isActive, index, onComplete, onAbort, onE
|
|
|
55
60
|
return;
|
|
56
61
|
const end = Date.now();
|
|
57
62
|
setEndTime(end);
|
|
58
|
-
|
|
63
|
+
const errorDuration = calculateElapsed(start);
|
|
64
|
+
setElapsed(errorDuration);
|
|
59
65
|
setStatus(ExecutionStatus.Failed);
|
|
60
|
-
onError?.(index, err instanceof Error ? err.message : 'Unknown error');
|
|
66
|
+
onError?.(index, err instanceof Error ? err.message : 'Unknown error', errorDuration);
|
|
61
67
|
}
|
|
62
68
|
}
|
|
63
|
-
execute();
|
|
69
|
+
void execute();
|
|
64
70
|
return () => {
|
|
65
71
|
mounted = false;
|
|
66
72
|
};
|
|
67
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
68
73
|
}, [isActive]);
|
|
69
74
|
// Handle abort when task becomes inactive while running
|
|
70
75
|
useEffect(() => {
|
|
@@ -77,5 +82,5 @@ export function Task({ label, command, isActive, index, onComplete, onAbort, onE
|
|
|
77
82
|
onAbort?.(index);
|
|
78
83
|
}
|
|
79
84
|
}, [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 }));
|
|
85
|
+
return (_jsx(Subtask, { label: label, command: command, status: status, isActive: isActive, startTime: startTime, endTime: endTime, elapsed: status === ExecutionStatus.Running ? currentElapsed : elapsed }));
|
|
81
86
|
}
|