prompt-language-shell 0.7.2 → 0.7.6
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 +3 -4
- 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 +94 -35
- package/dist/services/skills.js +7 -4
- package/dist/services/utils.js +16 -0
- package/dist/services/validator.js +10 -78
- package/dist/skills/answer.md +2 -2
- package/dist/skills/execute.md +3 -3
- package/dist/skills/introspect.md +13 -13
- package/dist/skills/schedule.md +403 -0
- package/dist/skills/validate.md +2 -3
- package/dist/tools/answer.tool.js +1 -1
- package/dist/tools/configure.tool.js +1 -1
- package/dist/tools/execute.tool.js +1 -1
- package/dist/tools/introspect.tool.js +3 -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 +4 -4
- 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 +4 -3
- package/dist/skills/plan.md +0 -875
- package/dist/tools/plan.tool.js +0 -36
package/README.md
CHANGED
|
@@ -28,7 +28,7 @@ $ pls list skills
|
|
|
28
28
|
Here's what I can help with:
|
|
29
29
|
|
|
30
30
|
- Introspect - list available capabilities and skills
|
|
31
|
-
-
|
|
31
|
+
- Configure - manage and configure system settings
|
|
32
32
|
- Answer - respond to questions and provide information
|
|
33
33
|
- Execute - run shell commands and process operations
|
|
34
34
|
```
|
|
@@ -74,10 +74,10 @@ Run `pls` without arguments to see the welcome screen.
|
|
|
74
74
|
## How It Works
|
|
75
75
|
|
|
76
76
|
When you make a request, `pls` interprets your intent and creates a structured
|
|
77
|
-
plan breaking down the work into individual tasks. You'll see this
|
|
77
|
+
plan breaking down the work into individual tasks. You'll see this schedule
|
|
78
78
|
displayed in your terminal before anything executes.
|
|
79
79
|
|
|
80
|
-
After reviewing the
|
|
80
|
+
After reviewing the schedule, you can confirm to proceed or cancel if something
|
|
81
81
|
doesn't look right. Once confirmed, `pls` executes each task sequentially and
|
|
82
82
|
shows real-time progress and results.
|
|
83
83
|
|
|
@@ -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 configure tool only
|
|
78
|
+
if (toolName === 'configure') {
|
|
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,19 +97,67 @@ function executeTasksAfterConfirm(tasks, service, userRequest, handlers) {
|
|
|
86
97
|
handlers.onError(error instanceof Error ? error.message : String(error));
|
|
87
98
|
return;
|
|
88
99
|
}
|
|
89
|
-
const
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
100
|
+
const scheduledTasks = tasks;
|
|
101
|
+
// Process tasks in order, preserving Group boundaries
|
|
102
|
+
// Track consecutive standalone tasks to group them by type
|
|
103
|
+
let consecutiveStandaloneTasks = [];
|
|
104
|
+
const processStandaloneTasks = () => {
|
|
105
|
+
if (consecutiveStandaloneTasks.length === 0)
|
|
106
|
+
return;
|
|
107
|
+
// Group consecutive standalone tasks by type
|
|
108
|
+
const tasksByType = {};
|
|
109
|
+
for (const type of Object.values(TaskType)) {
|
|
110
|
+
tasksByType[type] = [];
|
|
111
|
+
}
|
|
112
|
+
for (const task of consecutiveStandaloneTasks) {
|
|
113
|
+
tasksByType[task.type].push(task);
|
|
114
|
+
}
|
|
115
|
+
// Route each type group
|
|
116
|
+
for (const [type, typeTasks] of Object.entries(tasksByType)) {
|
|
117
|
+
const taskType = type;
|
|
118
|
+
if (typeTasks.length === 0)
|
|
119
|
+
continue;
|
|
120
|
+
routeTasksByType(taskType, typeTasks, service, userRequest, handlers);
|
|
121
|
+
}
|
|
122
|
+
consecutiveStandaloneTasks = [];
|
|
123
|
+
};
|
|
124
|
+
// Process tasks in original order
|
|
125
|
+
for (const task of scheduledTasks) {
|
|
126
|
+
if (task.type === TaskType.Group && task.subtasks) {
|
|
127
|
+
// Process any accumulated standalone tasks first
|
|
128
|
+
processStandaloneTasks();
|
|
129
|
+
// Process Group as separate component
|
|
130
|
+
if (task.subtasks.length > 0) {
|
|
131
|
+
const subtasks = task.subtasks;
|
|
132
|
+
const taskType = subtasks[0].type;
|
|
133
|
+
routeTasksByType(taskType, subtasks, service, userRequest, handlers);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
// Accumulate standalone task
|
|
138
|
+
consecutiveStandaloneTasks.push(task);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
// Process any remaining standalone tasks
|
|
142
|
+
processStandaloneTasks();
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Route tasks by type to appropriate components
|
|
146
|
+
* Extracted to allow reuse for both Groups and standalone tasks
|
|
147
|
+
*/
|
|
148
|
+
function routeTasksByType(taskType, typeTasks, service, userRequest, handlers) {
|
|
149
|
+
if (taskType === TaskType.Answer) {
|
|
150
|
+
// Create separate Answer component for each question
|
|
151
|
+
for (const task of typeTasks) {
|
|
152
|
+
handlers.addToQueue(createAnswerDefinition(task.action, service));
|
|
153
|
+
}
|
|
95
154
|
}
|
|
96
|
-
else if (
|
|
97
|
-
handlers.addToQueue(createIntrospectDefinition(
|
|
155
|
+
else if (taskType === TaskType.Introspect) {
|
|
156
|
+
handlers.addToQueue(createIntrospectDefinition(typeTasks, service));
|
|
98
157
|
}
|
|
99
|
-
else if (
|
|
158
|
+
else if (taskType === TaskType.Config) {
|
|
100
159
|
// Route to Config flow - extract keys from task params
|
|
101
|
-
const configKeys =
|
|
160
|
+
const configKeys = typeTasks
|
|
102
161
|
.map((task) => task.params?.key)
|
|
103
162
|
.filter((key) => key !== undefined);
|
|
104
163
|
handlers.addToQueue(createConfigDefinitionWithKeys(configKeys, (config) => {
|
|
@@ -121,10 +180,10 @@ function executeTasksAfterConfirm(tasks, service, userRequest, handlers) {
|
|
|
121
180
|
handlers.onAborted(operation);
|
|
122
181
|
}));
|
|
123
182
|
}
|
|
124
|
-
else {
|
|
183
|
+
else if (taskType === TaskType.Execute) {
|
|
125
184
|
// Execute tasks with validation
|
|
126
185
|
try {
|
|
127
|
-
const validation = validateExecuteTasks(
|
|
186
|
+
const validation = validateExecuteTasks(typeTasks);
|
|
128
187
|
if (validation.validationErrors.length > 0) {
|
|
129
188
|
// Show error feedback for invalid skills
|
|
130
189
|
const errorMessages = validation.validationErrors.map((error) => {
|
|
@@ -139,13 +198,13 @@ function executeTasksAfterConfirm(tasks, service, userRequest, handlers) {
|
|
|
139
198
|
handlers.addToQueue(createValidateDefinition(validation.missingConfig, userRequest, service, (error) => {
|
|
140
199
|
handlers.onError(error);
|
|
141
200
|
}, () => {
|
|
142
|
-
handlers.addToQueue(createExecuteDefinition(
|
|
201
|
+
handlers.addToQueue(createExecuteDefinition(typeTasks, service));
|
|
143
202
|
}, (operation) => {
|
|
144
203
|
handlers.onAborted(operation);
|
|
145
204
|
}));
|
|
146
205
|
}
|
|
147
206
|
else {
|
|
148
|
-
handlers.addToQueue(createExecuteDefinition(
|
|
207
|
+
handlers.addToQueue(createExecuteDefinition(typeTasks, service));
|
|
149
208
|
}
|
|
150
209
|
}
|
|
151
210
|
catch (error) {
|
package/dist/services/skills.js
CHANGED
|
@@ -7,10 +7,10 @@ import { parseSkillMarkdown, displayNameToKey } from './parser.js';
|
|
|
7
7
|
* Built-in skill names that user skills cannot override
|
|
8
8
|
*/
|
|
9
9
|
const BUILT_IN_SKILLS = new Set([
|
|
10
|
-
'
|
|
10
|
+
'schedule',
|
|
11
11
|
'execute',
|
|
12
12
|
'answer',
|
|
13
|
-
'
|
|
13
|
+
'configure',
|
|
14
14
|
'validate',
|
|
15
15
|
'introspect',
|
|
16
16
|
]);
|
|
@@ -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
|
}
|
package/dist/skills/answer.md
CHANGED
|
@@ -13,8 +13,8 @@ training data.
|
|
|
13
13
|
## Execution Flow
|
|
14
14
|
|
|
15
15
|
This tool is invoked AFTER:
|
|
16
|
-
1.
|
|
17
|
-
2. User reviewed and confirmed the
|
|
16
|
+
1. SCHEDULE detected an information request and created a task with type "answer"
|
|
17
|
+
2. User reviewed and confirmed the schedule
|
|
18
18
|
3. The answer task is now being executed
|
|
19
19
|
|
|
20
20
|
Your task is to provide a clear, concise answer to the user's question.
|
package/dist/skills/execute.md
CHANGED
|
@@ -7,11 +7,11 @@ operations when tasks with type "execute" have been planned and confirmed.
|
|
|
7
7
|
## Execution Flow
|
|
8
8
|
|
|
9
9
|
This tool is invoked AFTER:
|
|
10
|
-
1.
|
|
11
|
-
2. User reviewed and confirmed the
|
|
10
|
+
1. SCHEDULE created tasks with type "execute" describing operations to perform
|
|
11
|
+
2. User reviewed and confirmed the schedule
|
|
12
12
|
3. The execute tasks are now being executed
|
|
13
13
|
|
|
14
|
-
Your task is to translate the
|
|
14
|
+
Your task is to translate the scheduled actions into specific shell commands
|
|
15
15
|
that can be run in the terminal.
|
|
16
16
|
|
|
17
17
|
## Input
|