prompt-language-shell 0.7.2 → 0.7.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -1
- package/dist/services/anthropic.js +31 -23
- package/dist/services/colors.js +10 -4
- package/dist/services/components.js +2 -2
- package/dist/services/refinement.js +1 -1
- package/dist/services/registry.js +2 -2
- package/dist/services/router.js +118 -81
- package/dist/services/skills.js +5 -2
- package/dist/services/utils.js +16 -0
- package/dist/services/validator.js +10 -78
- package/dist/skills/introspect.md +11 -11
- package/dist/skills/schedule.md +357 -0
- package/dist/skills/validate.md +2 -3
- package/dist/tools/schedule.tool.js +55 -0
- package/dist/tools/validate.tool.js +1 -1
- package/dist/types/types.js +3 -2
- package/dist/ui/Command.js +15 -8
- package/dist/ui/Component.js +3 -3
- package/dist/ui/Debug.js +2 -3
- package/dist/ui/Introspect.js +3 -3
- package/dist/ui/List.js +3 -2
- package/dist/ui/{Plan.js → Schedule.js} +25 -4
- package/dist/ui/Validate.js +1 -1
- package/package.json +1 -1
- package/dist/skills/plan.md +0 -875
- package/dist/tools/plan.tool.js +0 -36
package/README.md
CHANGED
|
@@ -159,7 +159,6 @@ $ pls build test
|
|
|
159
159
|
|
|
160
160
|
## Roadmap
|
|
161
161
|
|
|
162
|
-
- **0.7** - Comprehend skill, simplified prompts, better debugging
|
|
163
162
|
- **0.8** - Sequential and interlaced skill execution
|
|
164
163
|
- **0.9** - Learn skill, codebase refinement, complex dependency handling
|
|
165
164
|
- **1.0** - Production release
|
|
@@ -52,31 +52,39 @@ export class AnthropicService {
|
|
|
52
52
|
this.client = new Anthropic({ apiKey: key });
|
|
53
53
|
this.model = model;
|
|
54
54
|
}
|
|
55
|
-
async processWithTool(command, toolName) {
|
|
55
|
+
async processWithTool(command, toolName, customInstructions) {
|
|
56
56
|
// Load tool from registry
|
|
57
57
|
const tool = toolRegistry.getSchema(toolName);
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
toolName === 'introspect' ||
|
|
64
|
-
toolName === 'execute' ||
|
|
65
|
-
toolName === 'validate') {
|
|
66
|
-
const skills = loadSkillsWithValidation();
|
|
67
|
-
const skillsSection = formatSkillsForPrompt(skills);
|
|
68
|
-
systemPrompt += skillsSection;
|
|
58
|
+
// Use custom instructions if provided, otherwise load from registry
|
|
59
|
+
let systemPrompt;
|
|
60
|
+
if (customInstructions) {
|
|
61
|
+
// Custom instructions provided (typically for testing)
|
|
62
|
+
systemPrompt = customInstructions;
|
|
69
63
|
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
64
|
+
else {
|
|
65
|
+
// Load and build system prompt automatically (production)
|
|
66
|
+
const instructions = toolRegistry.getInstructions(toolName);
|
|
67
|
+
systemPrompt = instructions;
|
|
68
|
+
// Add skills section for applicable tools
|
|
69
|
+
if (toolName === 'schedule' ||
|
|
70
|
+
toolName === 'introspect' ||
|
|
71
|
+
toolName === 'execute' ||
|
|
72
|
+
toolName === 'validate') {
|
|
73
|
+
const skills = loadSkillsWithValidation();
|
|
74
|
+
const skillsSection = formatSkillsForPrompt(skills);
|
|
75
|
+
systemPrompt += skillsSection;
|
|
76
|
+
}
|
|
77
|
+
// Add config structure for config tool only
|
|
78
|
+
if (toolName === 'config') {
|
|
79
|
+
const configStructure = getAvailableConfigStructure();
|
|
80
|
+
const configuredKeys = getConfiguredKeys();
|
|
81
|
+
const configSection = '\n## Available Configuration\n\n' +
|
|
82
|
+
'Config structure (key: description):\n' +
|
|
83
|
+
JSON.stringify(configStructure, null, 2) +
|
|
84
|
+
'\n\nConfigured keys (keys that exist in config file):\n' +
|
|
85
|
+
JSON.stringify(configuredKeys, null, 2);
|
|
86
|
+
systemPrompt += configSection;
|
|
87
|
+
}
|
|
80
88
|
}
|
|
81
89
|
// Build tools array - add web search for answer tool
|
|
82
90
|
const tools = [tool];
|
|
@@ -177,7 +185,7 @@ export class AnthropicService {
|
|
|
177
185
|
debug,
|
|
178
186
|
};
|
|
179
187
|
}
|
|
180
|
-
// Handle
|
|
188
|
+
// Handle schedule and introspect tool responses
|
|
181
189
|
if (input.message === undefined || typeof input.message !== 'string') {
|
|
182
190
|
throw new Error('Invalid tool response: missing or invalid message field');
|
|
183
191
|
}
|
package/dist/services/colors.js
CHANGED
|
@@ -57,7 +57,7 @@ export const Colors = {
|
|
|
57
57
|
},
|
|
58
58
|
Type: {
|
|
59
59
|
Config: Palette.Cyan,
|
|
60
|
-
|
|
60
|
+
Schedule: Palette.LightCyan,
|
|
61
61
|
Execute: Palette.Green,
|
|
62
62
|
Answer: Palette.Purple,
|
|
63
63
|
Introspect: Palette.Purple,
|
|
@@ -66,6 +66,7 @@ export const Colors = {
|
|
|
66
66
|
Ignore: Palette.BurntOrange,
|
|
67
67
|
Select: Palette.SteelBlue,
|
|
68
68
|
Discard: Palette.DarkOrange,
|
|
69
|
+
Group: Palette.Yellow,
|
|
69
70
|
},
|
|
70
71
|
Origin: {
|
|
71
72
|
BuiltIn: Palette.Cyan,
|
|
@@ -81,9 +82,9 @@ const taskColors = {
|
|
|
81
82
|
description: Colors.Label.Default,
|
|
82
83
|
type: Colors.Type.Config,
|
|
83
84
|
},
|
|
84
|
-
[TaskType.
|
|
85
|
+
[TaskType.Schedule]: {
|
|
85
86
|
description: Colors.Label.Default,
|
|
86
|
-
type: Colors.Type.
|
|
87
|
+
type: Colors.Type.Schedule,
|
|
87
88
|
},
|
|
88
89
|
[TaskType.Execute]: {
|
|
89
90
|
description: Colors.Label.Default,
|
|
@@ -117,6 +118,10 @@ const taskColors = {
|
|
|
117
118
|
description: Colors.Label.Discarded,
|
|
118
119
|
type: Colors.Type.Discard,
|
|
119
120
|
},
|
|
121
|
+
[TaskType.Group]: {
|
|
122
|
+
description: Colors.Label.Default,
|
|
123
|
+
type: Colors.Type.Group,
|
|
124
|
+
},
|
|
120
125
|
};
|
|
121
126
|
/**
|
|
122
127
|
* Feedback-specific color mappings (internal)
|
|
@@ -181,7 +186,7 @@ export function getTextColor(isCurrent) {
|
|
|
181
186
|
*/
|
|
182
187
|
const verboseTaskTypeLabels = {
|
|
183
188
|
[TaskType.Config]: 'configure option',
|
|
184
|
-
[TaskType.
|
|
189
|
+
[TaskType.Schedule]: 'schedule tasks',
|
|
185
190
|
[TaskType.Execute]: 'execute command',
|
|
186
191
|
[TaskType.Answer]: 'answer question',
|
|
187
192
|
[TaskType.Introspect]: 'introspect capabilities',
|
|
@@ -190,6 +195,7 @@ const verboseTaskTypeLabels = {
|
|
|
190
195
|
[TaskType.Ignore]: 'ignore request',
|
|
191
196
|
[TaskType.Select]: 'select option',
|
|
192
197
|
[TaskType.Discard]: 'discard option',
|
|
198
|
+
[TaskType.Group]: 'group tasks',
|
|
193
199
|
};
|
|
194
200
|
/**
|
|
195
201
|
* Get task type label based on debug level.
|
|
@@ -216,10 +216,10 @@ export function createCommandDefinition(command, service) {
|
|
|
216
216
|
},
|
|
217
217
|
};
|
|
218
218
|
}
|
|
219
|
-
export function
|
|
219
|
+
export function createScheduleDefinition(message, tasks, onSelectionConfirmed) {
|
|
220
220
|
return {
|
|
221
221
|
id: randomUUID(),
|
|
222
|
-
name: ComponentName.
|
|
222
|
+
name: ComponentName.Schedule,
|
|
223
223
|
status: ComponentStatus.Awaiting,
|
|
224
224
|
state: {
|
|
225
225
|
highlightedIndex: null,
|
|
@@ -21,7 +21,7 @@ export async function handleRefinement(selectedTasks, service, originalCommand,
|
|
|
21
21
|
})
|
|
22
22
|
.join(', ');
|
|
23
23
|
// Call LLM to refine plan with selected tasks
|
|
24
|
-
const refinedResult = await service.processWithTool(refinedCommand, '
|
|
24
|
+
const refinedResult = await service.processWithTool(refinedCommand, 'schedule');
|
|
25
25
|
// Complete the Refinement component
|
|
26
26
|
handlers.completeActive();
|
|
27
27
|
// Add debug components to timeline if present
|
|
@@ -37,14 +37,14 @@ import { answerTool } from '../tools/answer.tool.js';
|
|
|
37
37
|
import { configureTool } from '../tools/configure.tool.js';
|
|
38
38
|
import { executeTool } from '../tools/execute.tool.js';
|
|
39
39
|
import { introspectTool } from '../tools/introspect.tool.js';
|
|
40
|
-
import {
|
|
40
|
+
import { scheduleTool } from '../tools/schedule.tool.js';
|
|
41
41
|
import { validateTool } from '../tools/validate.tool.js';
|
|
42
42
|
const tools = {
|
|
43
43
|
answer: answerTool,
|
|
44
44
|
configure: configureTool,
|
|
45
45
|
execute: executeTool,
|
|
46
46
|
introspect: introspectTool,
|
|
47
|
-
|
|
47
|
+
schedule: scheduleTool,
|
|
48
48
|
validate: validateTool,
|
|
49
49
|
};
|
|
50
50
|
for (const [name, schema] of Object.entries(tools)) {
|
package/dist/services/router.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { TaskType } from '../types/types.js';
|
|
2
|
-
import { createAnswerDefinition, createConfigDefinitionWithKeys, createConfirmDefinition, createExecuteDefinition, createFeedback, createIntrospectDefinition, createMessage,
|
|
2
|
+
import { createAnswerDefinition, createConfigDefinitionWithKeys, createConfirmDefinition, createExecuteDefinition, createFeedback, createIntrospectDefinition, createMessage, createScheduleDefinition, createValidateDefinition, } from './components.js';
|
|
3
3
|
import { saveConfig, unflattenConfig } from './configuration.js';
|
|
4
4
|
import { FeedbackType } from '../types/types.js';
|
|
5
5
|
import { validateExecuteTasks } from './validator.js';
|
|
@@ -33,52 +33,63 @@ export function routeTasksWithConfirm(tasks, message, service, userRequest, hand
|
|
|
33
33
|
}
|
|
34
34
|
const operation = getOperationName(validTasks);
|
|
35
35
|
if (hasDefineTask) {
|
|
36
|
-
// Has DEFINE tasks - add
|
|
36
|
+
// Has DEFINE tasks - add Schedule to queue for user selection
|
|
37
37
|
// Refinement flow will call this function again with refined tasks
|
|
38
|
-
const
|
|
39
|
-
handlers.addToQueue(
|
|
38
|
+
const scheduleDefinition = createScheduleDefinition(message, validTasks);
|
|
39
|
+
handlers.addToQueue(scheduleDefinition);
|
|
40
40
|
}
|
|
41
41
|
else {
|
|
42
|
-
// No DEFINE tasks -
|
|
43
|
-
// When
|
|
44
|
-
// When
|
|
45
|
-
// When Confirm activates,
|
|
46
|
-
const
|
|
47
|
-
//
|
|
42
|
+
// No DEFINE tasks - Schedule auto-completes and adds Confirm to queue
|
|
43
|
+
// When Schedule activates, Command moves to timeline
|
|
44
|
+
// When Schedule completes, it moves to pending
|
|
45
|
+
// When Confirm activates, Schedule stays pending (visible for context)
|
|
46
|
+
const scheduleDefinition = createScheduleDefinition(message, validTasks, () => {
|
|
47
|
+
// Schedule completed - add Confirm to queue
|
|
48
48
|
const confirmDefinition = createConfirmDefinition(() => {
|
|
49
|
-
// User confirmed - complete both Confirm and
|
|
49
|
+
// User confirmed - complete both Confirm and Schedule, then route to appropriate component
|
|
50
50
|
handlers.completeActiveAndPending();
|
|
51
51
|
executeTasksAfterConfirm(validTasks, service, userRequest, handlers);
|
|
52
52
|
}, () => {
|
|
53
|
-
// User cancelled - complete both Confirm and
|
|
53
|
+
// User cancelled - complete both Confirm and Schedule, then show cancellation
|
|
54
54
|
handlers.completeActiveAndPending();
|
|
55
55
|
const message = getCancellationMessage(operation);
|
|
56
56
|
handlers.addToQueue(createFeedback(FeedbackType.Aborted, message));
|
|
57
57
|
});
|
|
58
58
|
handlers.addToQueue(confirmDefinition);
|
|
59
59
|
});
|
|
60
|
-
handlers.addToQueue(
|
|
60
|
+
handlers.addToQueue(scheduleDefinition);
|
|
61
61
|
}
|
|
62
62
|
}
|
|
63
63
|
/**
|
|
64
|
-
* Validate
|
|
65
|
-
*
|
|
64
|
+
* Validate task types - allows mixed types at top level with Groups,
|
|
65
|
+
* but each Group must have uniform subtask types
|
|
66
66
|
*/
|
|
67
67
|
function validateTaskTypes(tasks) {
|
|
68
68
|
if (tasks.length === 0)
|
|
69
69
|
return;
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
70
|
+
// Cast to ScheduledTask to access subtasks property
|
|
71
|
+
const scheduledTasks = tasks;
|
|
72
|
+
// Check each Group task's subtasks for uniform types
|
|
73
|
+
for (const task of scheduledTasks) {
|
|
74
|
+
if (task.type === TaskType.Group &&
|
|
75
|
+
task.subtasks &&
|
|
76
|
+
task.subtasks.length > 0) {
|
|
77
|
+
const subtaskTypes = new Set(task.subtasks.map((t) => t.type));
|
|
78
|
+
if (subtaskTypes.size > 1) {
|
|
79
|
+
throw new Error(getMixedTaskTypesError(Array.from(subtaskTypes)));
|
|
80
|
+
}
|
|
81
|
+
// Recursively validate nested groups
|
|
82
|
+
validateTaskTypes(task.subtasks);
|
|
83
|
+
}
|
|
73
84
|
}
|
|
74
85
|
}
|
|
75
86
|
/**
|
|
76
87
|
* Execute tasks after confirmation (internal helper)
|
|
77
|
-
* Validates task types
|
|
88
|
+
* Validates task types and routes each type appropriately
|
|
89
|
+
* Supports mixed types at top level with Groups
|
|
78
90
|
*/
|
|
79
91
|
function executeTasksAfterConfirm(tasks, service, userRequest, handlers) {
|
|
80
|
-
// Validate
|
|
81
|
-
// Per FLOWS.md: "Confirm component completes → Execution handler analyzes task types"
|
|
92
|
+
// Validate task types (Groups must have uniform subtasks)
|
|
82
93
|
try {
|
|
83
94
|
validateTaskTypes(tasks);
|
|
84
95
|
}
|
|
@@ -86,73 +97,99 @@ function executeTasksAfterConfirm(tasks, service, userRequest, handlers) {
|
|
|
86
97
|
handlers.onError(error instanceof Error ? error.message : String(error));
|
|
87
98
|
return;
|
|
88
99
|
}
|
|
89
|
-
|
|
90
|
-
const
|
|
91
|
-
const
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
100
|
+
// Flatten Group tasks to get actual executable subtasks
|
|
101
|
+
const flattenedTasks = [];
|
|
102
|
+
const scheduledTasks = tasks;
|
|
103
|
+
for (const task of scheduledTasks) {
|
|
104
|
+
if (task.type === TaskType.Group && task.subtasks) {
|
|
105
|
+
// Add all subtasks from the group
|
|
106
|
+
flattenedTasks.push(...task.subtasks);
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
// Add non-group tasks as-is
|
|
110
|
+
flattenedTasks.push(task);
|
|
111
|
+
}
|
|
95
112
|
}
|
|
96
|
-
|
|
97
|
-
|
|
113
|
+
// Group flattened tasks by type - initialize all TaskType keys with empty arrays
|
|
114
|
+
const tasksByType = {};
|
|
115
|
+
for (const type of Object.values(TaskType)) {
|
|
116
|
+
tasksByType[type] = [];
|
|
98
117
|
}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
118
|
+
for (const task of flattenedTasks) {
|
|
119
|
+
tasksByType[task.type].push(task);
|
|
120
|
+
}
|
|
121
|
+
// Route each type group appropriately
|
|
122
|
+
for (const [type, typeTasks] of Object.entries(tasksByType)) {
|
|
123
|
+
const taskType = type;
|
|
124
|
+
// Skip empty task groups (pre-initialized but unused)
|
|
125
|
+
if (typeTasks.length === 0) {
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
if (taskType === TaskType.Answer) {
|
|
129
|
+
const question = typeTasks[0].action;
|
|
130
|
+
handlers.addToQueue(createAnswerDefinition(question, service));
|
|
131
|
+
}
|
|
132
|
+
else if (taskType === TaskType.Introspect) {
|
|
133
|
+
handlers.addToQueue(createIntrospectDefinition(typeTasks, service));
|
|
134
|
+
}
|
|
135
|
+
else if (taskType === TaskType.Config) {
|
|
136
|
+
// Route to Config flow - extract keys from task params
|
|
137
|
+
const configKeys = typeTasks
|
|
138
|
+
.map((task) => task.params?.key)
|
|
139
|
+
.filter((key) => key !== undefined);
|
|
140
|
+
handlers.addToQueue(createConfigDefinitionWithKeys(configKeys, (config) => {
|
|
141
|
+
// Save config - Config component will handle completion and feedback
|
|
142
|
+
try {
|
|
143
|
+
// Convert flat dotted keys to nested structure grouped by section
|
|
144
|
+
const configBySection = unflattenConfig(config);
|
|
145
|
+
// Save each section
|
|
146
|
+
for (const [section, sectionConfig] of Object.entries(configBySection)) {
|
|
147
|
+
saveConfig(section, sectionConfig);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
catch (error) {
|
|
151
|
+
const errorMessage = error instanceof Error
|
|
152
|
+
? error.message
|
|
153
|
+
: 'Failed to save configuration';
|
|
154
|
+
throw new Error(errorMessage);
|
|
155
|
+
}
|
|
156
|
+
}, (operation) => {
|
|
157
|
+
handlers.onAborted(operation);
|
|
158
|
+
}));
|
|
159
|
+
}
|
|
160
|
+
else if (taskType === TaskType.Execute) {
|
|
161
|
+
// Execute tasks with validation
|
|
106
162
|
try {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
163
|
+
const validation = validateExecuteTasks(typeTasks);
|
|
164
|
+
if (validation.validationErrors.length > 0) {
|
|
165
|
+
// Show error feedback for invalid skills
|
|
166
|
+
const errorMessages = validation.validationErrors.map((error) => {
|
|
167
|
+
const issuesList = error.issues
|
|
168
|
+
.map((issue) => ` - ${issue}`)
|
|
169
|
+
.join('\n');
|
|
170
|
+
return `Invalid skill definition "${error.skill}":\n\n${issuesList}`;
|
|
171
|
+
});
|
|
172
|
+
handlers.addToQueue(createFeedback(FeedbackType.Failed, errorMessages.join('\n\n')));
|
|
173
|
+
}
|
|
174
|
+
else if (validation.missingConfig.length > 0) {
|
|
175
|
+
handlers.addToQueue(createValidateDefinition(validation.missingConfig, userRequest, service, (error) => {
|
|
176
|
+
handlers.onError(error);
|
|
177
|
+
}, () => {
|
|
178
|
+
handlers.addToQueue(createExecuteDefinition(typeTasks, service));
|
|
179
|
+
}, (operation) => {
|
|
180
|
+
handlers.onAborted(operation);
|
|
181
|
+
}));
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
handlers.addToQueue(createExecuteDefinition(typeTasks, service));
|
|
112
185
|
}
|
|
113
186
|
}
|
|
114
187
|
catch (error) {
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
}
|
|
120
|
-
}, (operation) => {
|
|
121
|
-
handlers.onAborted(operation);
|
|
122
|
-
}));
|
|
123
|
-
}
|
|
124
|
-
else {
|
|
125
|
-
// Execute tasks with validation
|
|
126
|
-
try {
|
|
127
|
-
const validation = validateExecuteTasks(tasks);
|
|
128
|
-
if (validation.validationErrors.length > 0) {
|
|
129
|
-
// Show error feedback for invalid skills
|
|
130
|
-
const errorMessages = validation.validationErrors.map((error) => {
|
|
131
|
-
const issuesList = error.issues
|
|
132
|
-
.map((issue) => ` - ${issue}`)
|
|
133
|
-
.join('\n');
|
|
134
|
-
return `Invalid skill definition "${error.skill}":\n\n${issuesList}`;
|
|
135
|
-
});
|
|
136
|
-
handlers.addToQueue(createFeedback(FeedbackType.Failed, errorMessages.join('\n\n')));
|
|
137
|
-
}
|
|
138
|
-
else if (validation.missingConfig.length > 0) {
|
|
139
|
-
handlers.addToQueue(createValidateDefinition(validation.missingConfig, userRequest, service, (error) => {
|
|
140
|
-
handlers.onError(error);
|
|
141
|
-
}, () => {
|
|
142
|
-
handlers.addToQueue(createExecuteDefinition(tasks, service));
|
|
143
|
-
}, (operation) => {
|
|
144
|
-
handlers.onAborted(operation);
|
|
145
|
-
}));
|
|
188
|
+
// Handle skill reference errors (e.g., unknown skills)
|
|
189
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
190
|
+
const message = createMessage(errorMessage);
|
|
191
|
+
handlers.addToQueue(message);
|
|
146
192
|
}
|
|
147
|
-
else {
|
|
148
|
-
handlers.addToQueue(createExecuteDefinition(tasks, service));
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
catch (error) {
|
|
152
|
-
// Handle skill reference errors (e.g., unknown skills)
|
|
153
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
154
|
-
const message = createMessage(errorMessage);
|
|
155
|
-
handlers.addToQueue(message);
|
|
156
193
|
}
|
|
157
194
|
}
|
|
158
195
|
}
|
package/dist/services/skills.js
CHANGED
|
@@ -146,8 +146,11 @@ brackets for additional information. Use commas instead. For example:
|
|
|
146
146
|
- WRONG: "Build project Alpha (the legacy version)"
|
|
147
147
|
|
|
148
148
|
`;
|
|
149
|
-
const
|
|
150
|
-
|
|
149
|
+
const separator = '-'.repeat(64);
|
|
150
|
+
const skillsContent = skills
|
|
151
|
+
.map((s) => s.trim())
|
|
152
|
+
.join('\n\n' + separator + '\n\n');
|
|
153
|
+
return header + separator + '\n\n' + skillsContent;
|
|
151
154
|
}
|
|
152
155
|
/**
|
|
153
156
|
* Parse skill reference from execution line
|
package/dist/services/utils.js
CHANGED
|
@@ -19,3 +19,19 @@ export function formatDuration(ms) {
|
|
|
19
19
|
}
|
|
20
20
|
return parts.join(' ');
|
|
21
21
|
}
|
|
22
|
+
/**
|
|
23
|
+
* Recursively extracts all leaf tasks from a hierarchical task structure.
|
|
24
|
+
* Leaf tasks are tasks without subtasks.
|
|
25
|
+
*/
|
|
26
|
+
export function getAllLeafTasks(tasks) {
|
|
27
|
+
const leafTasks = [];
|
|
28
|
+
for (const task of tasks) {
|
|
29
|
+
if (!task.subtasks || task.subtasks.length === 0) {
|
|
30
|
+
leafTasks.push(task);
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
leafTasks.push(...getAllLeafTasks(task.subtasks));
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return leafTasks;
|
|
37
|
+
}
|
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
import { extractPlaceholders, pathToString, resolveVariant, } from './resolver.js';
|
|
2
1
|
import { loadUserConfig, hasConfigPath } from './loader.js';
|
|
3
|
-
import { loadSkillDefinitions, createSkillLookup
|
|
4
|
-
import { getConfigType } from './parser.js';
|
|
2
|
+
import { loadSkillDefinitions, createSkillLookup } from './skills.js';
|
|
5
3
|
/**
|
|
6
4
|
* Validate config requirements for execute tasks
|
|
7
5
|
* Returns validation result with missing config and validation errors
|
|
@@ -38,88 +36,22 @@ export function validateExecuteTasks(tasks) {
|
|
|
38
36
|
};
|
|
39
37
|
}
|
|
40
38
|
for (const task of tasks) {
|
|
41
|
-
// Check
|
|
42
|
-
|
|
43
|
-
if (
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
if (!skill) {
|
|
47
|
-
continue;
|
|
48
|
-
}
|
|
49
|
-
// Get variant from task params (if any)
|
|
50
|
-
// Try params.variant first, then look for other param keys that might be the variant
|
|
51
|
-
let variant = null;
|
|
52
|
-
if (typeof task.params?.variant === 'string') {
|
|
53
|
-
variant = task.params.variant.toLowerCase();
|
|
54
|
-
}
|
|
55
|
-
else if (task.params && typeof task.params === 'object') {
|
|
56
|
-
// Look for other params that could be the variant (e.g., product, target, option, etc.)
|
|
57
|
-
// Exclude known non-variant params
|
|
58
|
-
const excludeKeys = new Set(['skill', 'type']);
|
|
59
|
-
for (const [key, value] of Object.entries(task.params)) {
|
|
60
|
-
if (!excludeKeys.has(key) && typeof value === 'string') {
|
|
61
|
-
variant = value.toLowerCase();
|
|
62
|
-
break;
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
// Expand skill references to get actual commands
|
|
67
|
-
const expanded = expandSkillReferences(skill.execution, skillLookup);
|
|
68
|
-
// Extract placeholders from actual commands
|
|
69
|
-
for (const line of expanded) {
|
|
70
|
-
const placeholders = extractPlaceholders(line);
|
|
71
|
-
for (const placeholder of placeholders) {
|
|
72
|
-
let resolvedPath;
|
|
73
|
-
if (placeholder.hasVariant) {
|
|
74
|
-
// Variant placeholder - resolve with variant from params
|
|
75
|
-
if (!variant) {
|
|
76
|
-
// No variant provided - skip this placeholder
|
|
77
|
-
continue;
|
|
78
|
-
}
|
|
79
|
-
const resolvedPathArray = resolveVariant(placeholder.path, variant);
|
|
80
|
-
resolvedPath = pathToString(resolvedPathArray);
|
|
81
|
-
}
|
|
82
|
-
else {
|
|
83
|
-
// Strict placeholder - use as-is
|
|
84
|
-
resolvedPath = pathToString(placeholder.path);
|
|
85
|
-
}
|
|
86
|
-
// Skip if already processed
|
|
87
|
-
if (seenPaths.has(resolvedPath)) {
|
|
88
|
-
continue;
|
|
89
|
-
}
|
|
90
|
-
seenPaths.add(resolvedPath);
|
|
91
|
-
// Check if config exists
|
|
92
|
-
if (!hasConfigPath(userConfig, resolvedPath)) {
|
|
93
|
-
// Get type from skill config
|
|
94
|
-
const type = skill.config
|
|
95
|
-
? getConfigType(skill.config, resolvedPath)
|
|
96
|
-
: undefined;
|
|
97
|
-
missing.push({
|
|
98
|
-
path: resolvedPath,
|
|
99
|
-
type: type || 'string',
|
|
100
|
-
});
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
else {
|
|
106
|
-
// Task doesn't come from a skill - check task action for placeholders
|
|
107
|
-
const placeholders = extractPlaceholders(task.action);
|
|
108
|
-
for (const placeholder of placeholders) {
|
|
109
|
-
// Skip variant placeholders - they should have been resolved during planning
|
|
110
|
-
if (placeholder.hasVariant) {
|
|
39
|
+
// Check task's config array from SCHEDULE tool
|
|
40
|
+
// This is the authoritative source for required configuration
|
|
41
|
+
if (task.config && task.config.length > 0) {
|
|
42
|
+
for (const configPath of task.config) {
|
|
43
|
+
if (typeof configPath !== 'string') {
|
|
111
44
|
continue;
|
|
112
45
|
}
|
|
113
|
-
const path = placeholder.path.join('.');
|
|
114
46
|
// Skip if already processed
|
|
115
|
-
if (seenPaths.has(
|
|
47
|
+
if (seenPaths.has(configPath)) {
|
|
116
48
|
continue;
|
|
117
49
|
}
|
|
118
|
-
seenPaths.add(
|
|
50
|
+
seenPaths.add(configPath);
|
|
119
51
|
// Check if config exists
|
|
120
|
-
if (!hasConfigPath(userConfig,
|
|
52
|
+
if (!hasConfigPath(userConfig, configPath)) {
|
|
121
53
|
missing.push({
|
|
122
|
-
path,
|
|
54
|
+
path: configPath,
|
|
123
55
|
type: 'string', // Default to string for now
|
|
124
56
|
});
|
|
125
57
|
}
|
|
@@ -3,14 +3,14 @@
|
|
|
3
3
|
You are the introspection execution component of "pls" (please), a
|
|
4
4
|
professional command-line concierge. Your role is to **execute** the listing
|
|
5
5
|
of available capabilities when a task with type "introspect" has been
|
|
6
|
-
|
|
6
|
+
scheduled and confirmed.
|
|
7
7
|
|
|
8
8
|
## Execution Flow
|
|
9
9
|
|
|
10
10
|
This tool is invoked AFTER:
|
|
11
|
-
1.
|
|
11
|
+
1. SCHEDULE detected an introspection request and created a task with type
|
|
12
12
|
"introspect"
|
|
13
|
-
2. User reviewed and confirmed the
|
|
13
|
+
2. User reviewed and confirmed the schedule
|
|
14
14
|
3. The introspect task is now being executed
|
|
15
15
|
|
|
16
16
|
Your task is to present available capabilities in a clear, organized list
|
|
@@ -71,7 +71,7 @@ NON-NEGOTIABLE and applies to EVERY response.
|
|
|
71
71
|
|
|
72
72
|
**DO NOT:**
|
|
73
73
|
- Reorder capabilities based on alphabetical sorting
|
|
74
|
-
- Put
|
|
74
|
+
- Put Schedule or Report first (this is WRONG)
|
|
75
75
|
- Rearrange based on perceived importance
|
|
76
76
|
- Deviate from this order for any reason
|
|
77
77
|
|
|
@@ -90,8 +90,8 @@ These MUST appear FIRST, in this EXACT sequence:
|
|
|
90
90
|
|
|
91
91
|
These MUST appear AFTER Execute and BEFORE user skills:
|
|
92
92
|
|
|
93
|
-
5. **
|
|
94
|
-
6. **Validate** ← ALWAYS position 6 (after
|
|
93
|
+
5. **Schedule** ← NEVER FIRST, ALWAYS position 5 (after Execute)
|
|
94
|
+
6. **Validate** ← ALWAYS position 6 (after Schedule)
|
|
95
95
|
7. **Report** ← NEVER FIRST, ALWAYS position 7 (after Validate)
|
|
96
96
|
|
|
97
97
|
### 3. User-Defined Skills
|
|
@@ -113,10 +113,10 @@ Create tasks with type "introspect" for each capability. Each task should:
|
|
|
113
113
|
- **Action**: The capability name and a concise description
|
|
114
114
|
- Format: "Capability Name: description" (note: display format will use
|
|
115
115
|
" - " separator)
|
|
116
|
-
- **IMPORTANT**: Use title case for capability names (e.g., "
|
|
117
|
-
"Execute"), NOT all uppercase (NOT "
|
|
116
|
+
- **IMPORTANT**: Use title case for capability names (e.g., "Schedule",
|
|
117
|
+
"Execute"), NOT all uppercase (NOT "SCHEDULE", "EXECUTE")
|
|
118
118
|
- Examples:
|
|
119
|
-
- "
|
|
119
|
+
- "Schedule: break down requests into actionable steps"
|
|
120
120
|
- "Execute: run shell commands and process operations"
|
|
121
121
|
- "Deploy Application: build and deploy to staging or production"
|
|
122
122
|
- **Type**: Always use "introspect"
|
|
@@ -150,7 +150,7 @@ Examples:
|
|
|
150
150
|
When user asks "list your skills", create an introductory message like
|
|
151
151
|
"here are my capabilities:" followed by tasks for built-in capabilities
|
|
152
152
|
(Introspect, Config, Answer, Execute), then indirect workflow capabilities
|
|
153
|
-
(
|
|
153
|
+
(Schedule, Validate, Report).
|
|
154
154
|
|
|
155
155
|
Each task uses type "introspect" with an action describing the
|
|
156
156
|
capability.
|
|
@@ -167,7 +167,7 @@ deploy app skill with its description.
|
|
|
167
167
|
When user asks "what can you do" and user-defined skills like "process
|
|
168
168
|
data" and "backup files" exist, create an introductory message like "i can
|
|
169
169
|
help with these operations:" followed by all built-in capabilities
|
|
170
|
-
(Introspect, Config, Answer, Execute, Validate,
|
|
170
|
+
(Introspect, Config, Answer, Execute, Validate, Schedule, Report) plus the
|
|
171
171
|
user-defined skills. Each capability and skill becomes a task with type
|
|
172
172
|
"introspect".
|
|
173
173
|
|