prompt-language-shell 0.8.6 → 0.8.8
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/execution/processing.js +1 -0
- package/dist/services/anthropic.js +1 -0
- package/dist/services/colors.js +21 -11
- package/dist/services/messages.js +21 -0
- package/dist/services/refinement.js +5 -0
- package/dist/services/router.js +56 -32
- package/dist/skills/execute.md +79 -9
- package/dist/skills/schedule.md +121 -29
- package/dist/tools/execute.tool.js +4 -0
- package/dist/types/schemas.js +1 -0
- package/dist/ui/Config.js +6 -2
- package/dist/ui/Execute.js +22 -1
- package/dist/ui/Feedback.js +2 -1
- package/dist/ui/Label.js +3 -2
- package/dist/ui/List.js +3 -2
- package/dist/ui/Schedule.js +16 -11
- package/dist/ui/Workflow.js +2 -5
- package/package.json +1 -1
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.
|
|
@@ -147,3 +147,24 @@ export function formatErrorMessage(error) {
|
|
|
147
147
|
}
|
|
148
148
|
return rawMessage;
|
|
149
149
|
}
|
|
150
|
+
/**
|
|
151
|
+
* Returns an execution error message with varied phrasing.
|
|
152
|
+
* Randomly selects from variations to sound natural, like a concierge.
|
|
153
|
+
* Format: "[Cannot execute phrase]. [Error details]."
|
|
154
|
+
*/
|
|
155
|
+
export function getExecutionErrorMessage(error) {
|
|
156
|
+
const prefixes = [
|
|
157
|
+
"I can't execute this",
|
|
158
|
+
"I'm unable to execute this",
|
|
159
|
+
"I can't proceed with this",
|
|
160
|
+
"I'm unable to proceed with this",
|
|
161
|
+
'This cannot be executed',
|
|
162
|
+
];
|
|
163
|
+
const prefix = prefixes[Math.floor(Math.random() * prefixes.length)];
|
|
164
|
+
// Capitalize first letter of error
|
|
165
|
+
const capitalizedError = error.charAt(0).toUpperCase() + error.slice(1);
|
|
166
|
+
const errorWithPeriod = capitalizedError.endsWith('.')
|
|
167
|
+
? capitalizedError
|
|
168
|
+
: `${capitalizedError}.`;
|
|
169
|
+
return `${prefix}. ${errorWithPeriod}`;
|
|
170
|
+
}
|
|
@@ -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(', ');
|
package/dist/services/router.js
CHANGED
|
@@ -101,6 +101,60 @@ function executeTasksAfterConfirm(tasks, service, userRequest, workflowHandlers,
|
|
|
101
101
|
return;
|
|
102
102
|
}
|
|
103
103
|
const scheduledTasks = asScheduledTasks(tasks);
|
|
104
|
+
// Collect ALL Execute tasks (standalone and from groups) for upfront validation
|
|
105
|
+
const allExecuteTasks = [];
|
|
106
|
+
for (const task of scheduledTasks) {
|
|
107
|
+
if (task.type === TaskType.Execute) {
|
|
108
|
+
allExecuteTasks.push(task);
|
|
109
|
+
}
|
|
110
|
+
else if (task.type === TaskType.Group && task.subtasks) {
|
|
111
|
+
const subtasks = task.subtasks;
|
|
112
|
+
if (subtasks.length > 0 && subtasks[0].type === TaskType.Execute) {
|
|
113
|
+
allExecuteTasks.push(...subtasks);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
// Validate ALL Execute tasks together to collect ALL missing config upfront
|
|
118
|
+
if (allExecuteTasks.length > 0) {
|
|
119
|
+
try {
|
|
120
|
+
const validation = validateExecuteTasks(allExecuteTasks);
|
|
121
|
+
if (validation.validationErrors.length > 0) {
|
|
122
|
+
// Show error feedback for invalid skills
|
|
123
|
+
const errorMessages = validation.validationErrors.map((error) => {
|
|
124
|
+
const issuesList = error.issues
|
|
125
|
+
.map((issue) => ` - ${issue}`)
|
|
126
|
+
.join('\n');
|
|
127
|
+
return `Invalid skill definition "${error.skill}":\n\n${issuesList}`;
|
|
128
|
+
});
|
|
129
|
+
workflowHandlers.addToQueue(createFeedback(FeedbackType.Failed, errorMessages.join('\n\n')));
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
else if (validation.missingConfig.length > 0) {
|
|
133
|
+
// Missing config detected - create ONE Validate component for ALL missing config
|
|
134
|
+
workflowHandlers.addToQueue(createValidateDefinition(validation.missingConfig, userRequest, service, (error) => {
|
|
135
|
+
requestHandlers.onError(error);
|
|
136
|
+
}, () => {
|
|
137
|
+
// After config is complete, resume task routing
|
|
138
|
+
routeTasksAfterConfig(scheduledTasks, service, userRequest, workflowHandlers, requestHandlers);
|
|
139
|
+
}, (operation) => {
|
|
140
|
+
requestHandlers.onAborted(operation);
|
|
141
|
+
}));
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
catch (error) {
|
|
146
|
+
requestHandlers.onError(error instanceof Error ? error.message : String(error));
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
// No missing config - proceed with normal routing
|
|
151
|
+
routeTasksAfterConfig(scheduledTasks, service, userRequest, workflowHandlers, requestHandlers);
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Route tasks after config is complete (or when no config is needed)
|
|
155
|
+
* Processes tasks in order, grouping by type
|
|
156
|
+
*/
|
|
157
|
+
function routeTasksAfterConfig(scheduledTasks, service, userRequest, workflowHandlers, requestHandlers) {
|
|
104
158
|
// Process tasks in order, preserving Group boundaries
|
|
105
159
|
// Track consecutive standalone tasks to group them by type
|
|
106
160
|
let consecutiveStandaloneTasks = [];
|
|
@@ -197,37 +251,7 @@ function routeTasksByType(taskType, typeTasks, service, userRequest, workflowHan
|
|
|
197
251
|
}));
|
|
198
252
|
}
|
|
199
253
|
else if (taskType === TaskType.Execute) {
|
|
200
|
-
// Execute tasks
|
|
201
|
-
|
|
202
|
-
const validation = validateExecuteTasks(typeTasks);
|
|
203
|
-
if (validation.validationErrors.length > 0) {
|
|
204
|
-
// Show error feedback for invalid skills
|
|
205
|
-
const errorMessages = validation.validationErrors.map((error) => {
|
|
206
|
-
const issuesList = error.issues
|
|
207
|
-
.map((issue) => ` - ${issue}`)
|
|
208
|
-
.join('\n');
|
|
209
|
-
return `Invalid skill definition "${error.skill}":\n\n${issuesList}`;
|
|
210
|
-
});
|
|
211
|
-
workflowHandlers.addToQueue(createFeedback(FeedbackType.Failed, errorMessages.join('\n\n')));
|
|
212
|
-
}
|
|
213
|
-
else if (validation.missingConfig.length > 0) {
|
|
214
|
-
workflowHandlers.addToQueue(createValidateDefinition(validation.missingConfig, userRequest, service, (error) => {
|
|
215
|
-
requestHandlers.onError(error);
|
|
216
|
-
}, () => {
|
|
217
|
-
workflowHandlers.addToQueue(createExecuteDefinition(typeTasks, service));
|
|
218
|
-
}, (operation) => {
|
|
219
|
-
requestHandlers.onAborted(operation);
|
|
220
|
-
}));
|
|
221
|
-
}
|
|
222
|
-
else {
|
|
223
|
-
workflowHandlers.addToQueue(createExecuteDefinition(typeTasks, service));
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
catch (error) {
|
|
227
|
-
// Handle skill reference errors (e.g., unknown skills)
|
|
228
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
229
|
-
const message = createMessage(errorMessage);
|
|
230
|
-
workflowHandlers.addToQueue(message);
|
|
231
|
-
}
|
|
254
|
+
// Execute tasks (validation already happened upfront in executeTasksAfterConfirm)
|
|
255
|
+
workflowHandlers.addToQueue(createExecuteDefinition(typeTasks, service));
|
|
232
256
|
}
|
|
233
257
|
}
|
package/dist/skills/execute.md
CHANGED
|
@@ -26,9 +26,63 @@ You will receive:
|
|
|
26
26
|
|
|
27
27
|
## Skill-Based Command Generation
|
|
28
28
|
|
|
29
|
+
**CRITICAL**: The "Available Skills" section in the prompt defines the ONLY
|
|
30
|
+
skills you can execute. This is an EXHAUSTIVE and COMPLETE list. Do NOT
|
|
31
|
+
assume skills exist based on examples in these instructions.
|
|
32
|
+
|
|
29
33
|
**CRITICAL**: When tasks originate from a user-defined skill, you MUST use
|
|
30
34
|
the skill's **Execution** section to generate commands, NOT invent your own.
|
|
31
35
|
|
|
36
|
+
**CRITICAL VALIDATION**: Before generating ANY commands for skill-based
|
|
37
|
+
tasks, perform these checks in order:
|
|
38
|
+
|
|
39
|
+
1. **Verify "Available Skills" section exists**: If there is no
|
|
40
|
+
"Available Skills" section in the prompt, STOP immediately and return
|
|
41
|
+
an error response.
|
|
42
|
+
|
|
43
|
+
2. **Verify skill exists**: Check if the skill named in params.skill
|
|
44
|
+
actually exists in the "Available Skills" section below.
|
|
45
|
+
|
|
46
|
+
3. **Verify skill has Steps section**: Check if the skill definition
|
|
47
|
+
includes a "### Steps" section with step descriptions.
|
|
48
|
+
|
|
49
|
+
4. **Verify skill has Execution section**: Check if the skill definition
|
|
50
|
+
includes a "### Execution" section with actual commands.
|
|
51
|
+
|
|
52
|
+
5. **If ANY check fails**: STOP immediately and return an error response.
|
|
53
|
+
DO NOT generate commands. DO NOT invent commands. DO NOT make
|
|
54
|
+
assumptions about what commands should be run.
|
|
55
|
+
|
|
56
|
+
**Error Response Formats** (keep error messages concise):
|
|
57
|
+
|
|
58
|
+
No Available Skills section:
|
|
59
|
+
```
|
|
60
|
+
message: "Cannot execute:"
|
|
61
|
+
summary: "No skills available"
|
|
62
|
+
commands: []
|
|
63
|
+
error: "No skills available"
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Skill not found:
|
|
67
|
+
```
|
|
68
|
+
message: "Cannot execute:"
|
|
69
|
+
summary: "Skill not found"
|
|
70
|
+
commands: []
|
|
71
|
+
error: "Skill '[skill name]' not found"
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Skill missing Steps or Execution:
|
|
75
|
+
```
|
|
76
|
+
message: "Cannot execute:"
|
|
77
|
+
summary: "Incomplete skill"
|
|
78
|
+
commands: []
|
|
79
|
+
error: "Skill '[skill name]' is incomplete"
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
**IMPORTANT**: Error messages must be concise (under 50 characters). Avoid
|
|
83
|
+
technical jargon or detailed explanations. The error will be shown to the
|
|
84
|
+
user in a natural, conversational format.
|
|
85
|
+
|
|
32
86
|
### Understanding Skill Structure
|
|
33
87
|
|
|
34
88
|
User-defined skills have two key sections:
|
|
@@ -42,7 +96,7 @@ position.
|
|
|
42
96
|
|
|
43
97
|
1. **Identify skill tasks**: Check if tasks have params.skill
|
|
44
98
|
2. **Find the skill**: Look up the skill in "Available Skills" section
|
|
45
|
-
below
|
|
99
|
+
below (REQUIRED - must exist)
|
|
46
100
|
3. **Match tasks to Execution**: Each task action came from a Steps line;
|
|
47
101
|
use the corresponding Execution line for the command
|
|
48
102
|
4. **Substitute parameters**: Replace {PARAM} placeholders with actual
|
|
@@ -304,9 +358,13 @@ For complex multi-step operations:
|
|
|
304
358
|
❌ Setting unrealistic timeouts for long operations
|
|
305
359
|
❌ Running destructive commands without safeguards
|
|
306
360
|
❌ Ignoring task parameters when generating commands
|
|
307
|
-
❌ Inventing commands instead of using skill's Execution
|
|
308
|
-
|
|
361
|
+
❌ **CRITICAL: Inventing commands instead of using skill's Execution
|
|
362
|
+
section**
|
|
363
|
+
❌ **CRITICAL: Ignoring params.skill and making up your own commands**
|
|
364
|
+
❌ **CRITICAL: Generating commands when the skill doesn't exist in
|
|
365
|
+
Available Skills**
|
|
309
366
|
❌ Not substituting parameter placeholders in skill commands
|
|
367
|
+
❌ **CRITICAL: Assuming what commands to run when skill is missing**
|
|
310
368
|
|
|
311
369
|
✅ Match commands precisely to task descriptions
|
|
312
370
|
✅ Use task params to fill in specific values
|
|
@@ -314,6 +372,10 @@ For complex multi-step operations:
|
|
|
314
372
|
✅ Set appropriate timeouts for each operation type
|
|
315
373
|
✅ Include safety checks for destructive operations
|
|
316
374
|
✅ Generate portable commands when possible
|
|
375
|
+
✅ **CRITICAL: Verify skill exists in Available Skills before generating
|
|
376
|
+
commands**
|
|
377
|
+
✅ **CRITICAL: Return error response if skill not found, never invent
|
|
378
|
+
commands**
|
|
317
379
|
✅ Always use skill's Execution section when params.skill is present
|
|
318
380
|
✅ Replace all {PARAM} placeholders with values from task params
|
|
319
381
|
|
|
@@ -321,9 +383,17 @@ For complex multi-step operations:
|
|
|
321
383
|
|
|
322
384
|
Before returning commands:
|
|
323
385
|
|
|
324
|
-
1.
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
386
|
+
1. **CRITICAL: If tasks have params.skill, verify Available Skills
|
|
387
|
+
section exists**
|
|
388
|
+
2. **CRITICAL: If tasks have params.skill, verify the skill exists in
|
|
389
|
+
Available Skills section**
|
|
390
|
+
3. **CRITICAL: If tasks have params.skill, verify the skill has both
|
|
391
|
+
Steps and Execution sections**
|
|
392
|
+
4. **CRITICAL: If any validation fails, return error response with empty
|
|
393
|
+
commands array**
|
|
394
|
+
5. Verify each command matches its task description
|
|
395
|
+
6. Check that all task params are incorporated
|
|
396
|
+
7. Ensure paths are properly quoted
|
|
397
|
+
8. Confirm timeouts are reasonable for each operation
|
|
398
|
+
9. Validate that critical flags are set appropriately
|
|
399
|
+
10. Review for any safety concerns
|
package/dist/skills/schedule.md
CHANGED
|
@@ -4,6 +4,21 @@ You are the scheduling component of "pls" (please), a command-line
|
|
|
4
4
|
concierge. Your role is to organize user requests into hierarchical
|
|
5
5
|
task structures with high-level tasks and their subtasks.
|
|
6
6
|
|
|
7
|
+
**CRITICAL - Skill Matching Foundation**:
|
|
8
|
+
|
|
9
|
+
The ONLY skills you can execute are those explicitly listed in the
|
|
10
|
+
"Available Skills" section of the system prompt. This section may be
|
|
11
|
+
present with skills, present but empty, or missing entirely. Your
|
|
12
|
+
behavior must adapt accordingly:
|
|
13
|
+
|
|
14
|
+
- **Skills present**: Match user requests ONLY against listed skills
|
|
15
|
+
- **Empty or missing**: Create "ignore" tasks for ALL action verbs
|
|
16
|
+
|
|
17
|
+
All examples in these instructions (e.g., "build", "deploy", "process")
|
|
18
|
+
are for illustration only. They do NOT represent actual available
|
|
19
|
+
skills unless they appear in the "Available Skills" section of the
|
|
20
|
+
system prompt.
|
|
21
|
+
|
|
7
22
|
## Response Format
|
|
8
23
|
|
|
9
24
|
Every response MUST include a brief message (single sentence, max 64
|
|
@@ -53,21 +68,38 @@ Every task MUST have a type field. Use the appropriate type:
|
|
|
53
68
|
- `answer` - Answering questions, explaining concepts
|
|
54
69
|
- `introspect` - Listing capabilities when user asks what you can do
|
|
55
70
|
- `report` - Generating summaries, displaying results
|
|
56
|
-
- `define` - Presenting options when
|
|
71
|
+
- `define` - Presenting options when a matching skill needs variant
|
|
72
|
+
selection
|
|
57
73
|
- `ignore` - Request has NO matching skill OR is too vague to execute
|
|
58
74
|
|
|
59
|
-
**CRITICAL
|
|
60
|
-
|
|
61
|
-
|
|
75
|
+
**CRITICAL SKILL MATCHING RULES**:
|
|
76
|
+
|
|
77
|
+
1. **ONLY match against skills in "Available Skills" section**: The
|
|
78
|
+
ONLY skills you can execute are those explicitly listed in the
|
|
79
|
+
"Available Skills" section of the prompt. Do NOT assume, infer, or
|
|
80
|
+
create skills based on examples in these instructions.
|
|
81
|
+
|
|
82
|
+
2. **Examples are illustrative only**: All examples in these
|
|
83
|
+
instructions (including "build", "deploy", etc.) are for
|
|
84
|
+
illustration purposes. They do NOT represent actual available
|
|
85
|
+
skills unless they appear in the "Available Skills" section.
|
|
62
86
|
|
|
63
|
-
**
|
|
87
|
+
3. **No Available Skills = No Execute Tasks**: If the "Available
|
|
88
|
+
Skills" section is missing or empty, ALL action verbs must result
|
|
89
|
+
in `ignore` type tasks. You cannot execute ANY commands without
|
|
90
|
+
explicitly defined skills.
|
|
91
|
+
|
|
92
|
+
4. **Define vs Ignore**:
|
|
93
|
+
- Use `define` ONLY when a skill EXISTS in "Available Skills" but
|
|
94
|
+
needs variant selection
|
|
95
|
+
- Use `ignore` when NO matching skill exists in "Available Skills"
|
|
96
|
+
|
|
97
|
+
**Define task params** (ONLY when skill exists): When creating a
|
|
98
|
+
`define` type task for a skill that EXISTS in "Available Skills",
|
|
99
|
+
include:
|
|
64
100
|
- `skill`: the skill name that needs variant selection (REQUIRED)
|
|
65
101
|
- `options`: array of option strings describing each variant (REQUIRED)
|
|
66
102
|
|
|
67
|
-
Example: User "build" without variant → Task with type "define",
|
|
68
|
-
params { skill: "Build Project", options: ["Build project Alpha, the
|
|
69
|
-
main variant", "Build project Beta, the experimental variant"] }
|
|
70
|
-
|
|
71
103
|
## Configuration Requests
|
|
72
104
|
|
|
73
105
|
When user wants to configure or change settings (e.g., "config",
|
|
@@ -93,15 +125,22 @@ Before creating tasks, evaluate the request type:
|
|
|
93
125
|
"search"
|
|
94
126
|
- Example: "explain docker" → answer type
|
|
95
127
|
|
|
96
|
-
3. **Action requests** (commands) - Must match
|
|
97
|
-
|
|
98
|
-
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
128
|
+
3. **Action requests** (commands) - Must match skills in "Available
|
|
129
|
+
Skills" section:
|
|
130
|
+
- Check if action verb matches ANY skill in "Available Skills"
|
|
131
|
+
section
|
|
132
|
+
- If verb matches a skill → examine the skill's Execution section
|
|
133
|
+
to determine structure:
|
|
134
|
+
- Multiple execution steps → create ONLY a group task with those
|
|
135
|
+
steps as subtasks (never create a flat execute task)
|
|
136
|
+
- Single execution step → can use a leaf execute task
|
|
137
|
+
- If verb does NOT match any skill in "Available Skills" → ignore
|
|
138
|
+
type with action "Ignore unknown 'X' request" where X is the
|
|
139
|
+
verb/phrase
|
|
140
|
+
- Example: "compile" with no matching skill in "Available Skills"
|
|
141
|
+
→ action "Ignore unknown 'compile' request"
|
|
142
|
+
- Example: "build" with no matching skill in "Available Skills" →
|
|
143
|
+
action "Ignore unknown 'build' request"
|
|
105
144
|
|
|
106
145
|
4. **Vague/ambiguous requests** without clear verb:
|
|
107
146
|
- Phrases like "do something", "handle it" → ignore type
|
|
@@ -128,6 +167,22 @@ components (e.g., {project.VARIANT.path}, {env.TYPE.config},
|
|
|
128
167
|
- Example: "build alpha" → variant is "alpha"
|
|
129
168
|
- Example: "deploy to staging" → variant is "staging"
|
|
130
169
|
- Example: "process experimental" → variant is "experimental"
|
|
170
|
+
- **CRITICAL**: If the variant CANNOT be identified from the user's
|
|
171
|
+
request, you MUST create a DEFINE task instead (see step 1a below)
|
|
172
|
+
|
|
173
|
+
1a. **When variant is unclear** - Create a DEFINE task:
|
|
174
|
+
- **NEVER use placeholder values** like `<UNKNOWN>`, `UNKNOWN`, or any
|
|
175
|
+
other placeholder
|
|
176
|
+
- **NEVER leave variant unresolved** or use temporary values
|
|
177
|
+
- **ALWAYS create a DEFINE task** with type "define" that includes:
|
|
178
|
+
- params.skill: the skill name requiring variant selection
|
|
179
|
+
- params.options: array of descriptive options for each available
|
|
180
|
+
variant
|
|
181
|
+
- Example: User says "deploy" without specifying environment → Create
|
|
182
|
+
DEFINE task with options like "Deploy to staging environment" and
|
|
183
|
+
"Deploy to production environment"
|
|
184
|
+
- The define task will prompt the user to select the variant before
|
|
185
|
+
execution continues
|
|
131
186
|
|
|
132
187
|
2. **Normalize to lowercase**: Convert variant name to lowercase
|
|
133
188
|
- "Alpha" → "alpha"
|
|
@@ -160,6 +215,19 @@ components (e.g., {project.VARIANT.path}, {env.TYPE.config},
|
|
|
160
215
|
{project.beta.config}` should include config:
|
|
161
216
|
["project.beta.repo", "project.beta.config"]
|
|
162
217
|
|
|
218
|
+
6. **Multi-step skills MUST use group structure**:
|
|
219
|
+
- **CRITICAL**: When a skill has multiple execution steps, it MUST
|
|
220
|
+
be represented as a group task with those steps as subtasks
|
|
221
|
+
- **NEVER use a flat execute task** for multi-step skills
|
|
222
|
+
- Single execution step: Can be represented as a leaf execute task
|
|
223
|
+
- Multiple execution steps: ALWAYS use group structure, never flat
|
|
224
|
+
- Note: The same skill can appear multiple times if the user
|
|
225
|
+
requests it in sequence (e.g., "deploy alpha, test, deploy beta")
|
|
226
|
+
- Each occurrence must still use group structure
|
|
227
|
+
- Example: "deploy alpha" → "Deploy Alpha" (group) with subtasks
|
|
228
|
+
- Example: "deploy alpha, test, deploy alpha" → "Deploy Alpha"
|
|
229
|
+
(group), "Run tests" (execute), "Deploy Alpha" (group)
|
|
230
|
+
|
|
163
231
|
**Examples**:
|
|
164
232
|
|
|
165
233
|
User request with variant placeholder
|
|
@@ -188,6 +256,10 @@ User request with multiple config expressions
|
|
|
188
256
|
- Multiple config expressions from the same task's commands
|
|
189
257
|
|
|
190
258
|
**Critical Rules**:
|
|
259
|
+
- **NEVER use placeholder values** like `<UNKNOWN>`, `UNKNOWN`, or
|
|
260
|
+
leave variant unresolved
|
|
261
|
+
- **If variant cannot be determined** from user request, create a
|
|
262
|
+
DEFINE task with options
|
|
191
263
|
- NEVER leave uppercase placeholder components unresolved
|
|
192
264
|
- The uppercase word can be ANY name (VARIANT, TARGET, TYPE,
|
|
193
265
|
PRODUCT, etc.)
|
|
@@ -269,20 +341,40 @@ even if they use the same action verb.
|
|
|
269
341
|
|
|
270
342
|
## Strict Skill Matching
|
|
271
343
|
|
|
272
|
-
|
|
273
|
-
|
|
344
|
+
**CRITICAL - Examples Are NOT Real Skills:**
|
|
345
|
+
|
|
346
|
+
- **All examples in these instructions are for illustration ONLY**:
|
|
347
|
+
Examples like "build", "deploy", "process" are NOT real skills
|
|
348
|
+
- **ONLY the Available Skills section contains real skills**: The
|
|
349
|
+
Available Skills section in the system prompt is the ONLY source of
|
|
350
|
+
truth
|
|
351
|
+
- **Never use example skills**: Do NOT create tasks based on skills
|
|
352
|
+
mentioned in examples unless they appear in Available Skills
|
|
353
|
+
- **When no Available Skills section exists**: ALL action verbs must
|
|
354
|
+
result in "ignore" type tasks
|
|
355
|
+
|
|
356
|
+
**CRITICAL**: Skills in the "Available Skills" section define the ONLY
|
|
357
|
+
operations you can execute. This is an EXHAUSTIVE and COMPLETE list.
|
|
274
358
|
|
|
275
359
|
**EXHAUSTIVE and EXCLUSIVE rules:**
|
|
276
360
|
|
|
277
|
-
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
361
|
+
- **ONLY skills in "Available Skills" section exist**: The skills
|
|
362
|
+
listed in the "Available Skills" section are the ONLY skills
|
|
363
|
+
available. Do NOT assume skills exist based on examples in these
|
|
364
|
+
instructions.
|
|
365
|
+
- **Empty or missing "Available Skills" = NO execute tasks**: If there
|
|
366
|
+
is no "Available Skills" section, or if it's empty, you CANNOT
|
|
367
|
+
create ANY execute tasks. ALL action verbs must result in "ignore"
|
|
368
|
+
type tasks.
|
|
369
|
+
- **The list is COMPLETE**: The "Available Skills" list is exhaustive.
|
|
370
|
+
There are no hidden or implicit skills.
|
|
371
|
+
- **No matching skill = ignore task**: If an action verb does NOT have
|
|
372
|
+
a matching skill in "Available Skills", you MUST create an "ignore"
|
|
373
|
+
type task
|
|
374
|
+
- **NO assumptions**: There are NO implicit or assumed operations
|
|
375
|
+
- **NO inference**: DO NOT infer follow-up actions based on context
|
|
376
|
+
- **NO related operations**: DO NOT assume operations even if they
|
|
377
|
+
seem logically related to a matched skill
|
|
286
378
|
|
|
287
379
|
**Common verbs that need skills:**
|
|
288
380
|
|
|
@@ -42,6 +42,10 @@ export const executeTool = {
|
|
|
42
42
|
required: ['description', 'command'],
|
|
43
43
|
},
|
|
44
44
|
},
|
|
45
|
+
error: {
|
|
46
|
+
type: 'string',
|
|
47
|
+
description: 'Error message when execution cannot proceed. Only include this field when returning an empty commands array due to validation failure (e.g., skill not found, missing Steps/Execution sections). Describes what went wrong.',
|
|
48
|
+
},
|
|
45
49
|
},
|
|
46
50
|
required: ['message', 'summary', 'commands'],
|
|
47
51
|
},
|
package/dist/types/schemas.js
CHANGED
|
@@ -90,6 +90,7 @@ export const CommandResultSchema = z.object({
|
|
|
90
90
|
tasks: z.array(ScheduledTaskSchema),
|
|
91
91
|
answer: z.string().optional(),
|
|
92
92
|
commands: z.array(ExecuteCommandSchema).optional(),
|
|
93
|
+
error: z.string().optional(),
|
|
93
94
|
debug: z.array(ComponentDefinitionSchema).optional(),
|
|
94
95
|
});
|
|
95
96
|
/**
|
package/dist/ui/Config.js
CHANGED
|
@@ -201,11 +201,15 @@ export function Config(props) {
|
|
|
201
201
|
selectedIndex,
|
|
202
202
|
};
|
|
203
203
|
requestHandlers.onCompleted(finalState);
|
|
204
|
+
// Abort configuration
|
|
204
205
|
if (onAborted) {
|
|
206
|
+
// Let Workflow handler complete and add feedback
|
|
205
207
|
onAborted('configuration');
|
|
206
208
|
}
|
|
207
|
-
|
|
208
|
-
|
|
209
|
+
else {
|
|
210
|
+
// Fallback: complete with abort feedback directly
|
|
211
|
+
lifecycleHandlers.completeActive(createFeedback(FeedbackType.Aborted, 'Configuration cancelled.'));
|
|
212
|
+
}
|
|
209
213
|
return;
|
|
210
214
|
}
|
|
211
215
|
// Handle selection step navigation
|
package/dist/ui/Execute.js
CHANGED
|
@@ -4,13 +4,14 @@ import { Box, Text } from 'ink';
|
|
|
4
4
|
import { ComponentStatus, } from '../types/components.js';
|
|
5
5
|
import { getTextColor } from '../services/colors.js';
|
|
6
6
|
import { useInput } from '../services/keyboard.js';
|
|
7
|
-
import { formatErrorMessage } from '../services/messages.js';
|
|
7
|
+
import { formatErrorMessage, getExecutionErrorMessage, } from '../services/messages.js';
|
|
8
8
|
import { ExecutionStatus } from '../services/shell.js';
|
|
9
9
|
import { ensureMinimumTime } from '../services/timing.js';
|
|
10
10
|
import { buildAbortedState, handleTaskCompletion, handleTaskFailure, } from '../execution/handlers.js';
|
|
11
11
|
import { processTasks } from '../execution/processing.js';
|
|
12
12
|
import { executeReducer, initialState } from '../execution/reducer.js';
|
|
13
13
|
import { ExecuteActionType } from '../execution/types.js';
|
|
14
|
+
import { createMessage, markAsDone } from '../services/components.js';
|
|
14
15
|
import { Message } from './Message.js';
|
|
15
16
|
import { Spinner } from './Spinner.js';
|
|
16
17
|
import { Task } from './Task.js';
|
|
@@ -101,6 +102,26 @@ export function Execute({ tasks, status, service, requestHandlers, lifecycleHand
|
|
|
101
102
|
workflowHandlers.addToTimeline(...result.debug);
|
|
102
103
|
}
|
|
103
104
|
if (result.commands.length === 0) {
|
|
105
|
+
// Check if this is an error response (has error field)
|
|
106
|
+
if (result.error) {
|
|
107
|
+
// Add error message to timeline
|
|
108
|
+
const errorMessage = getExecutionErrorMessage(result.error);
|
|
109
|
+
workflowHandlers.addToTimeline(markAsDone(createMessage(errorMessage)));
|
|
110
|
+
// Complete without error in state (message already in timeline)
|
|
111
|
+
const finalState = {
|
|
112
|
+
message: result.message,
|
|
113
|
+
summary: '',
|
|
114
|
+
taskInfos: [],
|
|
115
|
+
completed: 0,
|
|
116
|
+
taskExecutionTimes: [],
|
|
117
|
+
completionMessage: null,
|
|
118
|
+
error: null,
|
|
119
|
+
};
|
|
120
|
+
requestHandlers.onCompleted(finalState);
|
|
121
|
+
lifecycleHandlers.completeActive();
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
// No commands and no error - just complete
|
|
104
125
|
dispatch({
|
|
105
126
|
type: ExecuteActionType.ProcessingComplete,
|
|
106
127
|
payload: { message: result.message },
|
package/dist/ui/Feedback.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { Box, Text } from 'ink';
|
|
3
|
+
import { ComponentStatus } from '../types/components.js';
|
|
3
4
|
import { FeedbackType } from '../types/types.js';
|
|
4
5
|
import { getFeedbackColor } from '../services/colors.js';
|
|
5
6
|
function getSymbol(type) {
|
|
@@ -12,7 +13,7 @@ function getSymbol(type) {
|
|
|
12
13
|
}[type];
|
|
13
14
|
}
|
|
14
15
|
export function Feedback({ type, message }) {
|
|
15
|
-
const color = getFeedbackColor(type,
|
|
16
|
+
const color = getFeedbackColor(type, ComponentStatus.Done);
|
|
16
17
|
const symbol = getSymbol(type);
|
|
17
18
|
return (_jsx(Box, { marginLeft: 1, children: _jsxs(Text, { color: color, children: [symbol, " ", message] }) }));
|
|
18
19
|
}
|
package/dist/ui/Label.js
CHANGED
|
@@ -3,7 +3,8 @@ import { Box, Text } from 'ink';
|
|
|
3
3
|
import { getTaskColors, getTaskTypeLabel } from '../services/colors.js';
|
|
4
4
|
import { DebugLevel } from '../configuration/types.js';
|
|
5
5
|
import { Separator } from './Separator.js';
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
import { ComponentStatus } from '../types/components.js';
|
|
7
|
+
export function Label({ description, taskType, showType = false, status = ComponentStatus.Done, debug = DebugLevel.None, }) {
|
|
8
|
+
const colors = getTaskColors(taskType, status);
|
|
8
9
|
return (_jsxs(Box, { children: [_jsx(Text, { color: colors.description, children: description }), showType && (_jsxs(_Fragment, { children: [_jsx(Separator, {}), _jsx(Text, { color: colors.type, children: getTaskTypeLabel(taskType, debug) })] }))] }));
|
|
9
10
|
}
|
package/dist/ui/List.js
CHANGED
|
@@ -4,7 +4,8 @@ import { Palette } from '../services/colors.js';
|
|
|
4
4
|
import { Separator } from './Separator.js';
|
|
5
5
|
export const List = ({ items, level = 0, highlightedIndex = null, highlightedParentIndex = null, showType = false, }) => {
|
|
6
6
|
const marginLeft = level > 0 ? 2 : 0;
|
|
7
|
-
|
|
7
|
+
const gap = level === 0 ? 1 : 0;
|
|
8
|
+
return (_jsx(Box, { flexDirection: "column", marginLeft: marginLeft, gap: gap, children: items.map((item, index) => {
|
|
8
9
|
// At level 0, track which parent is active for child highlighting
|
|
9
10
|
// At level > 0, only highlight if this parent is the active one
|
|
10
11
|
const shouldHighlightChildren = level === 0 ? highlightedParentIndex === index : false;
|
|
@@ -23,6 +24,6 @@ export const List = ({ items, level = 0, highlightedIndex = null, highlightedPar
|
|
|
23
24
|
(isHighlighted && item.type.highlightedColor
|
|
24
25
|
? item.type.highlightedColor
|
|
25
26
|
: Palette.White);
|
|
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));
|
|
27
|
+
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(Box, { marginTop: 1, children: _jsx(List, { items: item.children, level: level + 1, highlightedIndex: shouldHighlightChildren ? highlightedIndex : null, showType: showType }) }))] }, index));
|
|
27
28
|
}) }));
|
|
28
29
|
};
|
package/dist/ui/Schedule.js
CHANGED
|
@@ -3,17 +3,22 @@ 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 { getTaskColors, getTaskTypeLabel } from '../services/colors.js';
|
|
6
|
+
import { getTaskColors, getTaskTypeLabel, Palette, } from '../services/colors.js';
|
|
7
7
|
import { DebugLevel } from '../configuration/types.js';
|
|
8
8
|
import { useInput } from '../services/keyboard.js';
|
|
9
9
|
import { Label } from './Label.js';
|
|
10
10
|
import { List } from './List.js';
|
|
11
|
-
function taskToListItem(task, highlightedChildIndex = null, isDefineTaskWithoutSelection = false,
|
|
12
|
-
const taskColors = getTaskColors(task.type,
|
|
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
|
+
}
|
|
13
18
|
const item = {
|
|
14
19
|
description: {
|
|
15
20
|
text: task.action,
|
|
16
|
-
color:
|
|
21
|
+
color: descriptionColor,
|
|
17
22
|
},
|
|
18
23
|
type: { text: getTaskTypeLabel(task.type, debug), color: taskColors.type },
|
|
19
24
|
children: [],
|
|
@@ -21,7 +26,7 @@ function taskToListItem(task, highlightedChildIndex = null, isDefineTaskWithoutS
|
|
|
21
26
|
// Mark define tasks with right arrow when no selection has been made
|
|
22
27
|
if (isDefineTaskWithoutSelection) {
|
|
23
28
|
item.marker = ' → ';
|
|
24
|
-
item.markerColor = getTaskColors(TaskType.Schedule,
|
|
29
|
+
item.markerColor = getTaskColors(TaskType.Schedule, status).type;
|
|
25
30
|
}
|
|
26
31
|
// Add children for Define tasks with options
|
|
27
32
|
if (task.type === TaskType.Define && Array.isArray(task.params?.options)) {
|
|
@@ -33,8 +38,8 @@ function taskToListItem(task, highlightedChildIndex = null, isDefineTaskWithoutS
|
|
|
33
38
|
childType =
|
|
34
39
|
index === highlightedChildIndex ? TaskType.Execute : TaskType.Discard;
|
|
35
40
|
}
|
|
36
|
-
const colors = getTaskColors(childType,
|
|
37
|
-
const planColors = getTaskColors(TaskType.Schedule,
|
|
41
|
+
const colors = getTaskColors(childType, status);
|
|
42
|
+
const planColors = getTaskColors(TaskType.Schedule, status);
|
|
38
43
|
return {
|
|
39
44
|
description: {
|
|
40
45
|
text: option,
|
|
@@ -56,11 +61,11 @@ function taskToListItem(task, highlightedChildIndex = null, isDefineTaskWithoutS
|
|
|
56
61
|
Array.isArray(scheduledTask.subtasks) &&
|
|
57
62
|
scheduledTask.subtasks.length > 0) {
|
|
58
63
|
item.children = scheduledTask.subtasks.map((subtask) => {
|
|
59
|
-
const subtaskColors = getTaskColors(subtask.type,
|
|
64
|
+
const subtaskColors = getTaskColors(subtask.type, status);
|
|
60
65
|
return {
|
|
61
66
|
description: {
|
|
62
67
|
text: subtask.action,
|
|
63
|
-
color:
|
|
68
|
+
color: Palette.AshGray,
|
|
64
69
|
},
|
|
65
70
|
type: {
|
|
66
71
|
text: getTaskTypeLabel(subtask.type, debug),
|
|
@@ -107,9 +112,9 @@ export const ScheduleView = ({ message, tasks, state, status, debug = DebugLevel
|
|
|
107
112
|
defineGroupIndex === currentDefineGroupIndex &&
|
|
108
113
|
highlightedIndex === null &&
|
|
109
114
|
isActive;
|
|
110
|
-
return taskToListItem(task, childIndex, isDefineWithoutSelection,
|
|
115
|
+
return taskToListItem(task, childIndex, isDefineWithoutSelection, status, debug);
|
|
111
116
|
});
|
|
112
|
-
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,
|
|
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 }) })] }));
|
|
113
118
|
};
|
|
114
119
|
/**
|
|
115
120
|
* Schedule controller: Manages task selection and navigation
|
package/dist/ui/Workflow.js
CHANGED
|
@@ -47,12 +47,9 @@ export const Workflow = ({ initialQueue, debug }) => {
|
|
|
47
47
|
},
|
|
48
48
|
onAborted: (operation) => {
|
|
49
49
|
moveActiveToTimeline();
|
|
50
|
-
//
|
|
50
|
+
// Clear queue and add only feedback to prevent subsequent components from executing
|
|
51
51
|
const message = getCancellationMessage(operation);
|
|
52
|
-
setQueue((
|
|
53
|
-
...queue,
|
|
54
|
-
createFeedback(FeedbackType.Aborted, message),
|
|
55
|
-
]);
|
|
52
|
+
setQueue([createFeedback(FeedbackType.Aborted, message)]);
|
|
56
53
|
},
|
|
57
54
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-parameters
|
|
58
55
|
onCompleted: (finalState) => {
|