prompt-language-shell 0.8.6 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -1
- package/dist/configuration/io.js +22 -1
- package/dist/configuration/types.js +3 -4
- package/dist/execution/handlers.js +20 -29
- package/dist/execution/processing.js +13 -1
- package/dist/execution/reducer.js +17 -37
- package/dist/execution/utils.js +6 -0
- package/dist/services/anthropic.js +1 -0
- package/dist/services/colors.js +21 -11
- package/dist/services/components.js +1 -2
- package/dist/services/filesystem.js +21 -1
- package/dist/services/messages.js +15 -0
- package/dist/services/process.js +7 -2
- package/dist/services/refinement.js +5 -0
- package/dist/services/router.js +136 -82
- package/dist/services/shell.js +179 -10
- package/dist/services/skills.js +2 -1
- package/dist/skills/answer.md +14 -12
- package/dist/skills/execute.md +139 -28
- package/dist/skills/introspect.md +9 -9
- package/dist/skills/schedule.md +121 -35
- package/dist/tools/execute.tool.js +4 -0
- package/dist/types/errors.js +47 -0
- package/dist/types/result.js +40 -0
- package/dist/types/schemas.js +1 -0
- package/dist/ui/Component.js +2 -2
- package/dist/ui/Config.js +6 -2
- package/dist/ui/Execute.js +146 -102
- package/dist/ui/Feedback.js +2 -1
- package/dist/ui/Label.js +3 -2
- package/dist/ui/List.js +3 -2
- package/dist/ui/Output.js +54 -0
- package/dist/ui/Schedule.js +16 -11
- package/dist/ui/Task.js +99 -10
- package/dist/ui/Workflow.js +2 -5
- package/package.json +1 -1
package/README.md
CHANGED
package/dist/configuration/io.js
CHANGED
|
@@ -61,11 +61,32 @@ export function mergeConfig(existingContent, sectionName, newValues) {
|
|
|
61
61
|
}
|
|
62
62
|
export function saveConfig(section, config, fs = defaultFileSystem) {
|
|
63
63
|
const configFile = getConfigFile();
|
|
64
|
+
const tempFile = `${configFile}.tmp`;
|
|
64
65
|
const existingContent = fs.exists(configFile)
|
|
65
66
|
? fs.readFile(configFile, 'utf-8')
|
|
66
67
|
: '';
|
|
67
68
|
const newContent = mergeConfig(existingContent, section, config);
|
|
68
|
-
|
|
69
|
+
try {
|
|
70
|
+
// Write to temp file first
|
|
71
|
+
fs.writeFile(tempFile, newContent);
|
|
72
|
+
// Validate the temp file can be parsed
|
|
73
|
+
const tempContent = fs.readFile(tempFile, 'utf-8');
|
|
74
|
+
parseYamlConfig(tempContent);
|
|
75
|
+
// Atomic rename (on POSIX systems)
|
|
76
|
+
fs.rename(tempFile, configFile);
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
// Clean up temp file if it exists
|
|
80
|
+
if (fs.exists(tempFile)) {
|
|
81
|
+
try {
|
|
82
|
+
fs.remove(tempFile);
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
// Ignore cleanup errors
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
throw error;
|
|
89
|
+
}
|
|
69
90
|
}
|
|
70
91
|
export function saveAnthropicConfig(config, fs = defaultFileSystem) {
|
|
71
92
|
saveConfig('anthropic', config, fs);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { AppError, ErrorCode } from '../types/errors.js';
|
|
1
2
|
export var AnthropicModel;
|
|
2
3
|
(function (AnthropicModel) {
|
|
3
4
|
AnthropicModel["Sonnet"] = "claude-sonnet-4-5";
|
|
@@ -20,11 +21,9 @@ export var ConfigDefinitionType;
|
|
|
20
21
|
ConfigDefinitionType["Number"] = "number";
|
|
21
22
|
ConfigDefinitionType["Boolean"] = "boolean";
|
|
22
23
|
})(ConfigDefinitionType || (ConfigDefinitionType = {}));
|
|
23
|
-
export class ConfigError extends
|
|
24
|
-
origin;
|
|
24
|
+
export class ConfigError extends AppError {
|
|
25
25
|
constructor(message, origin) {
|
|
26
|
-
super(message);
|
|
26
|
+
super(message, ErrorCode.MissingConfig, origin);
|
|
27
27
|
this.name = 'ConfigError';
|
|
28
|
-
this.origin = origin;
|
|
29
28
|
}
|
|
30
29
|
}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { ExecutionStatus } from '../services/shell.js';
|
|
2
2
|
import { formatDuration } from '../services/utils.js';
|
|
3
3
|
import { ExecuteActionType, } from './types.js';
|
|
4
|
+
import { getTotalElapsed } from './utils.js';
|
|
4
5
|
/**
|
|
5
6
|
* Handles task completion logic and returns the appropriate action and state.
|
|
6
7
|
*/
|
|
7
8
|
export function handleTaskCompletion(index, elapsed, context) {
|
|
8
|
-
const {
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
if (index < taskInfos.length - 1) {
|
|
9
|
+
const { tasks, message, summary } = context;
|
|
10
|
+
const updatedTaskInfos = tasks.map((task, i) => i === index ? { ...task, status: ExecutionStatus.Success, elapsed } : task);
|
|
11
|
+
if (index < tasks.length - 1) {
|
|
12
12
|
// More tasks to execute
|
|
13
13
|
return {
|
|
14
14
|
action: {
|
|
@@ -18,9 +18,8 @@ export function handleTaskCompletion(index, elapsed, context) {
|
|
|
18
18
|
finalState: {
|
|
19
19
|
message,
|
|
20
20
|
summary,
|
|
21
|
-
|
|
21
|
+
tasks: updatedTaskInfos,
|
|
22
22
|
completed: index + 1,
|
|
23
|
-
taskExecutionTimes: updatedTimes,
|
|
24
23
|
completionMessage: null,
|
|
25
24
|
error: null,
|
|
26
25
|
},
|
|
@@ -29,7 +28,7 @@ export function handleTaskCompletion(index, elapsed, context) {
|
|
|
29
28
|
}
|
|
30
29
|
// All tasks complete
|
|
31
30
|
const summaryText = summary.trim() || 'Execution completed';
|
|
32
|
-
const totalElapsed =
|
|
31
|
+
const totalElapsed = getTotalElapsed(updatedTaskInfos);
|
|
33
32
|
const completion = `${summaryText} in ${formatDuration(totalElapsed)}.`;
|
|
34
33
|
return {
|
|
35
34
|
action: {
|
|
@@ -39,9 +38,8 @@ export function handleTaskCompletion(index, elapsed, context) {
|
|
|
39
38
|
finalState: {
|
|
40
39
|
message,
|
|
41
40
|
summary,
|
|
42
|
-
|
|
41
|
+
tasks: updatedTaskInfos,
|
|
43
42
|
completed: index + 1,
|
|
44
|
-
taskExecutionTimes: updatedTimes,
|
|
45
43
|
completionMessage: completion,
|
|
46
44
|
error: null,
|
|
47
45
|
},
|
|
@@ -52,10 +50,10 @@ export function handleTaskCompletion(index, elapsed, context) {
|
|
|
52
50
|
* Handles task error logic and returns the appropriate action and state.
|
|
53
51
|
*/
|
|
54
52
|
export function handleTaskFailure(index, error, elapsed, context) {
|
|
55
|
-
const {
|
|
56
|
-
const task =
|
|
53
|
+
const { tasks, message, summary } = context;
|
|
54
|
+
const task = tasks[index];
|
|
57
55
|
const isCritical = task.command.critical !== false; // Default to true
|
|
58
|
-
const updatedTaskInfos =
|
|
56
|
+
const updatedTaskInfos = tasks.map((task, i) => i === index ? { ...task, status: ExecutionStatus.Failed, elapsed } : task);
|
|
59
57
|
if (isCritical) {
|
|
60
58
|
// Critical failure - stop execution
|
|
61
59
|
return {
|
|
@@ -66,19 +64,16 @@ export function handleTaskFailure(index, error, elapsed, context) {
|
|
|
66
64
|
finalState: {
|
|
67
65
|
message,
|
|
68
66
|
summary,
|
|
69
|
-
|
|
67
|
+
tasks: updatedTaskInfos,
|
|
70
68
|
completed: index + 1,
|
|
71
|
-
taskExecutionTimes,
|
|
72
69
|
completionMessage: null,
|
|
73
|
-
error,
|
|
70
|
+
error: null,
|
|
74
71
|
},
|
|
75
72
|
shouldComplete: true,
|
|
76
|
-
shouldReportError: true,
|
|
77
73
|
};
|
|
78
74
|
}
|
|
79
75
|
// Non-critical failure - continue to next task
|
|
80
|
-
|
|
81
|
-
if (index < taskInfos.length - 1) {
|
|
76
|
+
if (index < tasks.length - 1) {
|
|
82
77
|
return {
|
|
83
78
|
action: {
|
|
84
79
|
type: ExecuteActionType.TaskErrorContinue,
|
|
@@ -87,19 +82,18 @@ export function handleTaskFailure(index, error, elapsed, context) {
|
|
|
87
82
|
finalState: {
|
|
88
83
|
message,
|
|
89
84
|
summary,
|
|
90
|
-
|
|
85
|
+
tasks: updatedTaskInfos,
|
|
91
86
|
completed: index + 1,
|
|
92
|
-
taskExecutionTimes: updatedTimes,
|
|
93
87
|
completionMessage: null,
|
|
94
88
|
error: null,
|
|
95
89
|
},
|
|
96
90
|
shouldComplete: false,
|
|
97
|
-
shouldReportError: false,
|
|
98
91
|
};
|
|
99
92
|
}
|
|
100
|
-
// Last task, complete execution
|
|
93
|
+
// Last task failed (non-critical), complete execution
|
|
94
|
+
// Non-critical failures still show completion message with summary
|
|
101
95
|
const summaryText = summary.trim() || 'Execution completed';
|
|
102
|
-
const totalElapsed =
|
|
96
|
+
const totalElapsed = getTotalElapsed(updatedTaskInfos);
|
|
103
97
|
const completion = `${summaryText} in ${formatDuration(totalElapsed)}.`;
|
|
104
98
|
return {
|
|
105
99
|
action: {
|
|
@@ -109,26 +103,23 @@ export function handleTaskFailure(index, error, elapsed, context) {
|
|
|
109
103
|
finalState: {
|
|
110
104
|
message,
|
|
111
105
|
summary,
|
|
112
|
-
|
|
106
|
+
tasks: updatedTaskInfos,
|
|
113
107
|
completed: index + 1,
|
|
114
|
-
taskExecutionTimes: updatedTimes,
|
|
115
108
|
completionMessage: completion,
|
|
116
109
|
error: null,
|
|
117
110
|
},
|
|
118
111
|
shouldComplete: true,
|
|
119
|
-
shouldReportError: false,
|
|
120
112
|
};
|
|
121
113
|
}
|
|
122
114
|
/**
|
|
123
115
|
* Builds final state for task abortion.
|
|
124
116
|
*/
|
|
125
|
-
export function buildAbortedState(
|
|
117
|
+
export function buildAbortedState(tasks, message, summary, completed) {
|
|
126
118
|
return {
|
|
127
119
|
message,
|
|
128
120
|
summary,
|
|
129
|
-
|
|
121
|
+
tasks,
|
|
130
122
|
completed,
|
|
131
|
-
taskExecutionTimes,
|
|
132
123
|
completionMessage: null,
|
|
133
124
|
error: null,
|
|
134
125
|
};
|
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
import { loadUserConfig } from '../services/loader.js';
|
|
2
2
|
import { replacePlaceholders } from '../services/resolver.js';
|
|
3
3
|
import { validatePlaceholderResolution } from './validation.js';
|
|
4
|
+
/**
|
|
5
|
+
* Fix escaped quotes in commands
|
|
6
|
+
* JSON parsing removes backslashes before quotes in patterns like key="value"
|
|
7
|
+
* This restores them: key="value" -> key=\"value\"
|
|
8
|
+
*/
|
|
9
|
+
export function fixEscapedQuotes(command) {
|
|
10
|
+
// Replace ="value" with =\"value\"
|
|
11
|
+
return command.replace(/="([^"]*)"/g, '=\\"$1\\"');
|
|
12
|
+
}
|
|
4
13
|
/**
|
|
5
14
|
* Processes tasks through the AI service to generate executable commands.
|
|
6
15
|
* Resolves placeholders in task descriptions and validates the results.
|
|
@@ -22,7 +31,9 @@ export async function processTasks(tasks, service) {
|
|
|
22
31
|
const result = await service.processWithTool(taskDescriptions, 'execute');
|
|
23
32
|
// Resolve placeholders in command strings
|
|
24
33
|
const resolvedCommands = (result.commands || []).map((cmd) => {
|
|
25
|
-
|
|
34
|
+
// Fix escaped quotes lost in JSON parsing
|
|
35
|
+
const fixed = fixEscapedQuotes(cmd.command);
|
|
36
|
+
const resolved = replacePlaceholders(fixed, userConfig);
|
|
26
37
|
validatePlaceholderResolution(resolved);
|
|
27
38
|
return { ...cmd, command: resolved };
|
|
28
39
|
});
|
|
@@ -30,6 +41,7 @@ export async function processTasks(tasks, service) {
|
|
|
30
41
|
message: result.message,
|
|
31
42
|
summary: result.summary || '',
|
|
32
43
|
commands: resolvedCommands,
|
|
44
|
+
error: result.error,
|
|
33
45
|
debug: result.debug,
|
|
34
46
|
};
|
|
35
47
|
}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { ExecutionStatus } from '../services/shell.js';
|
|
2
2
|
import { formatDuration } from '../services/utils.js';
|
|
3
3
|
import { ExecuteActionType, } from './types.js';
|
|
4
|
+
import { getTotalElapsed } from './utils.js';
|
|
4
5
|
export const initialState = {
|
|
5
6
|
error: null,
|
|
6
|
-
|
|
7
|
+
tasks: [],
|
|
7
8
|
message: '',
|
|
8
9
|
completed: 0,
|
|
9
10
|
hasProcessed: false,
|
|
10
|
-
taskExecutionTimes: [],
|
|
11
11
|
completionMessage: null,
|
|
12
12
|
summary: '',
|
|
13
13
|
};
|
|
@@ -24,7 +24,7 @@ export function executeReducer(state, action) {
|
|
|
24
24
|
...state,
|
|
25
25
|
message: action.payload.message,
|
|
26
26
|
summary: action.payload.summary,
|
|
27
|
-
|
|
27
|
+
tasks: action.payload.tasks,
|
|
28
28
|
completed: 0,
|
|
29
29
|
};
|
|
30
30
|
case ExecuteActionType.ProcessingError:
|
|
@@ -34,11 +34,7 @@ export function executeReducer(state, action) {
|
|
|
34
34
|
hasProcessed: true,
|
|
35
35
|
};
|
|
36
36
|
case ExecuteActionType.TaskComplete: {
|
|
37
|
-
const
|
|
38
|
-
...state.taskExecutionTimes,
|
|
39
|
-
action.payload.elapsed,
|
|
40
|
-
];
|
|
41
|
-
const updatedTaskInfos = state.taskInfos.map((task, i) => i === action.payload.index
|
|
37
|
+
const updatedTaskInfos = state.tasks.map((task, i) => i === action.payload.index
|
|
42
38
|
? {
|
|
43
39
|
...task,
|
|
44
40
|
status: ExecutionStatus.Success,
|
|
@@ -47,49 +43,39 @@ export function executeReducer(state, action) {
|
|
|
47
43
|
: task);
|
|
48
44
|
return {
|
|
49
45
|
...state,
|
|
50
|
-
|
|
51
|
-
taskExecutionTimes: updatedTimes,
|
|
46
|
+
tasks: updatedTaskInfos,
|
|
52
47
|
completed: action.payload.index + 1,
|
|
53
48
|
};
|
|
54
49
|
}
|
|
55
50
|
case ExecuteActionType.AllTasksComplete: {
|
|
56
|
-
const
|
|
57
|
-
...state.taskExecutionTimes,
|
|
58
|
-
action.payload.elapsed,
|
|
59
|
-
];
|
|
60
|
-
const updatedTaskInfos = state.taskInfos.map((task, i) => i === action.payload.index
|
|
51
|
+
const updatedTaskInfos = state.tasks.map((task, i) => i === action.payload.index
|
|
61
52
|
? {
|
|
62
53
|
...task,
|
|
63
54
|
status: ExecutionStatus.Success,
|
|
64
55
|
elapsed: action.payload.elapsed,
|
|
65
56
|
}
|
|
66
57
|
: task);
|
|
67
|
-
const totalElapsed =
|
|
58
|
+
const totalElapsed = getTotalElapsed(updatedTaskInfos);
|
|
68
59
|
const completion = `${action.payload.summaryText} in ${formatDuration(totalElapsed)}.`;
|
|
69
60
|
return {
|
|
70
61
|
...state,
|
|
71
|
-
|
|
72
|
-
taskExecutionTimes: updatedTimes,
|
|
62
|
+
tasks: updatedTaskInfos,
|
|
73
63
|
completed: action.payload.index + 1,
|
|
74
64
|
completionMessage: completion,
|
|
75
65
|
};
|
|
76
66
|
}
|
|
77
67
|
case ExecuteActionType.TaskErrorCritical: {
|
|
78
|
-
const updatedTaskInfos = state.
|
|
68
|
+
const updatedTaskInfos = state.tasks.map((task, i) => i === action.payload.index
|
|
79
69
|
? { ...task, status: ExecutionStatus.Failed, elapsed: 0 }
|
|
80
70
|
: task);
|
|
81
71
|
return {
|
|
82
72
|
...state,
|
|
83
|
-
|
|
73
|
+
tasks: updatedTaskInfos,
|
|
84
74
|
error: action.payload.error,
|
|
85
75
|
};
|
|
86
76
|
}
|
|
87
77
|
case ExecuteActionType.TaskErrorContinue: {
|
|
88
|
-
const
|
|
89
|
-
...state.taskExecutionTimes,
|
|
90
|
-
action.payload.elapsed,
|
|
91
|
-
];
|
|
92
|
-
const updatedTaskInfos = state.taskInfos.map((task, i) => i === action.payload.index
|
|
78
|
+
const updatedTaskInfos = state.tasks.map((task, i) => i === action.payload.index
|
|
93
79
|
? {
|
|
94
80
|
...task,
|
|
95
81
|
status: ExecutionStatus.Failed,
|
|
@@ -98,35 +84,29 @@ export function executeReducer(state, action) {
|
|
|
98
84
|
: task);
|
|
99
85
|
return {
|
|
100
86
|
...state,
|
|
101
|
-
|
|
102
|
-
taskExecutionTimes: updatedTimes,
|
|
87
|
+
tasks: updatedTaskInfos,
|
|
103
88
|
completed: action.payload.index + 1,
|
|
104
89
|
};
|
|
105
90
|
}
|
|
106
91
|
case ExecuteActionType.LastTaskError: {
|
|
107
|
-
const
|
|
108
|
-
...state.taskExecutionTimes,
|
|
109
|
-
action.payload.elapsed,
|
|
110
|
-
];
|
|
111
|
-
const updatedTaskInfos = state.taskInfos.map((task, i) => i === action.payload.index
|
|
92
|
+
const updatedTaskInfos = state.tasks.map((task, i) => i === action.payload.index
|
|
112
93
|
? {
|
|
113
94
|
...task,
|
|
114
95
|
status: ExecutionStatus.Failed,
|
|
115
96
|
elapsed: action.payload.elapsed,
|
|
116
97
|
}
|
|
117
98
|
: task);
|
|
118
|
-
const totalElapsed =
|
|
99
|
+
const totalElapsed = getTotalElapsed(updatedTaskInfos);
|
|
119
100
|
const completion = `${action.payload.summaryText} in ${formatDuration(totalElapsed)}.`;
|
|
120
101
|
return {
|
|
121
102
|
...state,
|
|
122
|
-
|
|
123
|
-
taskExecutionTimes: updatedTimes,
|
|
103
|
+
tasks: updatedTaskInfos,
|
|
124
104
|
completed: action.payload.index + 1,
|
|
125
105
|
completionMessage: completion,
|
|
126
106
|
};
|
|
127
107
|
}
|
|
128
108
|
case ExecuteActionType.CancelExecution: {
|
|
129
|
-
const updatedTaskInfos = state.
|
|
109
|
+
const updatedTaskInfos = state.tasks.map((task, taskIndex) => {
|
|
130
110
|
if (taskIndex < action.payload.completed) {
|
|
131
111
|
return { ...task, status: ExecutionStatus.Success };
|
|
132
112
|
}
|
|
@@ -139,7 +119,7 @@ export function executeReducer(state, action) {
|
|
|
139
119
|
});
|
|
140
120
|
return {
|
|
141
121
|
...state,
|
|
142
|
-
|
|
122
|
+
tasks: updatedTaskInfos,
|
|
143
123
|
};
|
|
144
124
|
}
|
|
145
125
|
default:
|
package/dist/services/colors.js
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
import { DebugLevel } from '../configuration/types.js';
|
|
2
2
|
import { FeedbackType, Origin, TaskType } from '../types/types.js';
|
|
3
3
|
import { ExecutionStatus } from './shell.js';
|
|
4
|
+
import { ComponentStatus } from '../types/components.js';
|
|
4
5
|
/**
|
|
5
6
|
* Base color palette - raw color values with descriptive names.
|
|
6
7
|
* All colors used in the interface are defined here.
|
|
7
8
|
*/
|
|
8
9
|
export const Palette = {
|
|
9
10
|
White: '#ffffff',
|
|
11
|
+
SoftWhite: '#fafafa',
|
|
10
12
|
AshGray: '#d0d0d0',
|
|
13
|
+
LightGray: '#aaaaaa',
|
|
11
14
|
Gray: '#888888',
|
|
12
15
|
DarkGray: '#666666',
|
|
13
16
|
CharcoalGray: '#282828',
|
|
@@ -32,6 +35,7 @@ export const Palette = {
|
|
|
32
35
|
export const Colors = {
|
|
33
36
|
Text: {
|
|
34
37
|
Active: Palette.White,
|
|
38
|
+
Pending: Palette.SoftWhite,
|
|
35
39
|
Inactive: Palette.AshGray,
|
|
36
40
|
UserQuery: Palette.White,
|
|
37
41
|
},
|
|
@@ -148,12 +152,18 @@ const originColors = {
|
|
|
148
152
|
* - Colors.Text.Active for current items
|
|
149
153
|
* - Colors.Text.Inactive (undefined) for historical items
|
|
150
154
|
*/
|
|
151
|
-
function processColor(color,
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
155
|
+
function processColor(color, status) {
|
|
156
|
+
const getColor = () => {
|
|
157
|
+
switch (status) {
|
|
158
|
+
case ComponentStatus.Active:
|
|
159
|
+
return Colors.Text.Active;
|
|
160
|
+
case ComponentStatus.Pending:
|
|
161
|
+
return Colors.Text.Pending;
|
|
162
|
+
default:
|
|
163
|
+
return Colors.Text.Inactive;
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
return color || getColor();
|
|
157
167
|
}
|
|
158
168
|
/**
|
|
159
169
|
* Get task colors with current/historical state handling.
|
|
@@ -162,11 +172,11 @@ function processColor(color, isCurrent) {
|
|
|
162
172
|
* - Colors.Text.Inactive (undefined) for historical items
|
|
163
173
|
* - Colors.Text.Active for current items
|
|
164
174
|
*/
|
|
165
|
-
export function getTaskColors(type,
|
|
175
|
+
export function getTaskColors(type, status) {
|
|
166
176
|
const colors = taskColors[type];
|
|
167
177
|
return {
|
|
168
|
-
description: processColor(colors.description,
|
|
169
|
-
type: processColor(colors.type,
|
|
178
|
+
description: processColor(colors.description, status),
|
|
179
|
+
type: processColor(colors.type, status),
|
|
170
180
|
};
|
|
171
181
|
}
|
|
172
182
|
/**
|
|
@@ -176,8 +186,8 @@ export function getTaskColors(type, isCurrent) {
|
|
|
176
186
|
* - Colors.Text.Inactive (undefined) for historical items
|
|
177
187
|
* - Colors.Text.Active for current items
|
|
178
188
|
*/
|
|
179
|
-
export function getFeedbackColor(type,
|
|
180
|
-
return processColor(feedbackColors[type],
|
|
189
|
+
export function getFeedbackColor(type, status = ComponentStatus.Done) {
|
|
190
|
+
return processColor(feedbackColors[type], status);
|
|
181
191
|
}
|
|
182
192
|
/**
|
|
183
193
|
* Get color for capability origin.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync, } from 'fs';
|
|
1
|
+
import { existsSync, mkdirSync, readdirSync, readFileSync, renameSync, unlinkSync, writeFileSync, } from 'fs';
|
|
2
2
|
import { dirname } from 'path';
|
|
3
3
|
/**
|
|
4
4
|
* Real filesystem implementation using Node's fs module
|
|
@@ -19,6 +19,12 @@ export class RealFileSystem {
|
|
|
19
19
|
createDirectory(path, options) {
|
|
20
20
|
mkdirSync(path, options);
|
|
21
21
|
}
|
|
22
|
+
rename(oldPath, newPath) {
|
|
23
|
+
renameSync(oldPath, newPath);
|
|
24
|
+
}
|
|
25
|
+
remove(path) {
|
|
26
|
+
unlinkSync(path);
|
|
27
|
+
}
|
|
22
28
|
}
|
|
23
29
|
/**
|
|
24
30
|
* In-memory filesystem implementation for testing
|
|
@@ -93,6 +99,20 @@ export class MemoryFileSystem {
|
|
|
93
99
|
this.directories.add(path);
|
|
94
100
|
}
|
|
95
101
|
}
|
|
102
|
+
rename(oldPath, newPath) {
|
|
103
|
+
const content = this.files.get(oldPath);
|
|
104
|
+
if (content === undefined) {
|
|
105
|
+
throw new Error(`ENOENT: no such file or directory, rename '${oldPath}'`);
|
|
106
|
+
}
|
|
107
|
+
this.files.delete(oldPath);
|
|
108
|
+
this.files.set(newPath, content);
|
|
109
|
+
}
|
|
110
|
+
remove(path) {
|
|
111
|
+
if (!this.files.has(path)) {
|
|
112
|
+
throw new Error(`ENOENT: no such file or directory, unlink '${path}'`);
|
|
113
|
+
}
|
|
114
|
+
this.files.delete(path);
|
|
115
|
+
}
|
|
96
116
|
/**
|
|
97
117
|
* Clear all files and directories (useful for test cleanup)
|
|
98
118
|
*/
|
|
@@ -147,3 +147,18 @@ export function formatErrorMessage(error) {
|
|
|
147
147
|
}
|
|
148
148
|
return rawMessage;
|
|
149
149
|
}
|
|
150
|
+
/**
|
|
151
|
+
* Returns an execution error message with varied phrasing.
|
|
152
|
+
* Error details are shown in the task output, so this is just a summary.
|
|
153
|
+
* Randomly selects from variations to sound natural.
|
|
154
|
+
*/
|
|
155
|
+
export function getExecutionErrorMessage(_error) {
|
|
156
|
+
const messages = [
|
|
157
|
+
'The execution failed.',
|
|
158
|
+
'Execution has failed.',
|
|
159
|
+
'The execution was not successful.',
|
|
160
|
+
'Execution did not succeed.',
|
|
161
|
+
'The execution encountered an error.',
|
|
162
|
+
];
|
|
163
|
+
return messages[Math.floor(Math.random() * messages.length)];
|
|
164
|
+
}
|
package/dist/services/process.js
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
|
+
export const defaultProcessControl = {
|
|
2
|
+
exit: (code) => process.exit(code),
|
|
3
|
+
};
|
|
1
4
|
/**
|
|
2
5
|
* Exit application after brief delay to allow UI to render
|
|
3
6
|
*/
|
|
4
|
-
export function exitApp(code) {
|
|
5
|
-
setTimeout(() =>
|
|
7
|
+
export function exitApp(code, processControl = defaultProcessControl) {
|
|
8
|
+
setTimeout(() => {
|
|
9
|
+
processControl.exit(code);
|
|
10
|
+
}, 100);
|
|
6
11
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { TaskType } from '../types/types.js';
|
|
1
2
|
import { createRefinement } from './components.js';
|
|
2
3
|
import { formatErrorMessage, getRefiningMessage } from './messages.js';
|
|
3
4
|
import { routeTasksWithConfirm } from './router.js';
|
|
@@ -17,6 +18,10 @@ export async function handleRefinement(selectedTasks, service, originalCommand,
|
|
|
17
18
|
.map((task) => {
|
|
18
19
|
const action = task.action.toLowerCase().replace(/,/g, ' -');
|
|
19
20
|
const type = task.type;
|
|
21
|
+
// For execute/group tasks, use generic hint - let LLM decide based on skill
|
|
22
|
+
if (type === TaskType.Execute || type === TaskType.Group) {
|
|
23
|
+
return `${action} (shell execution)`;
|
|
24
|
+
}
|
|
20
25
|
return `${action} (type: ${type})`;
|
|
21
26
|
})
|
|
22
27
|
.join(', ');
|