prompt-language-shell 0.6.6 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +2 -1
- package/dist/services/anthropic.js +21 -2
- package/dist/services/components.js +11 -0
- package/dist/services/configuration.js +23 -5
- package/dist/services/logger.js +64 -0
- package/dist/services/messages.js +17 -2
- package/dist/services/{skill-parser.js → parser.js} +34 -15
- package/dist/services/refinement.js +5 -1
- package/dist/services/{tool-registry.js → registry.js} +14 -24
- package/dist/services/{task-router.js → router.js} +29 -21
- package/dist/services/skills.js +165 -17
- package/dist/services/{execution-validator.js → validator.js} +6 -8
- package/dist/{config/ANSWER.md → skills/answer.md} +10 -9
- package/dist/{config/CONFIG.md → skills/config.md} +16 -9
- package/dist/{config/EXECUTE.md → skills/execute.md} +91 -53
- package/dist/{config/INTROSPECT.md → skills/introspect.md} +63 -47
- package/dist/{config/PLAN.md → skills/plan.md} +419 -337
- package/dist/{config/VALIDATE.md → skills/validate.md} +26 -12
- package/dist/types/types.js +1 -0
- package/dist/ui/Command.js +5 -1
- package/dist/ui/Component.js +3 -0
- package/dist/ui/Config.js +3 -2
- package/dist/ui/Debug.js +8 -0
- package/dist/ui/Execute.js +2 -2
- package/dist/ui/Introspect.js +3 -2
- package/dist/ui/Main.js +19 -5
- package/dist/ui/Plan.js +3 -2
- package/dist/ui/Validate.js +8 -2
- package/dist/ui/Workflow.js +2 -1
- package/package.json +2 -2
- package/dist/services/skill-expander.js +0 -87
- /package/dist/services/{config-loader.js → loader.js} +0 -0
- /package/dist/services/{placeholder-resolver.js → resolver.js} +0 -0
package/dist/services/skills.js
CHANGED
|
@@ -1,7 +1,42 @@
|
|
|
1
1
|
import { existsSync, readdirSync, readFileSync } from 'fs';
|
|
2
2
|
import { homedir } from 'os';
|
|
3
3
|
import { join } from 'path';
|
|
4
|
-
import {
|
|
4
|
+
import { getUnknownSkillMessage } from './messages.js';
|
|
5
|
+
import { parseSkillMarkdown, displayNameToKey } from './parser.js';
|
|
6
|
+
/**
|
|
7
|
+
* Built-in skill names that user skills cannot override
|
|
8
|
+
*/
|
|
9
|
+
const BUILT_IN_SKILLS = new Set([
|
|
10
|
+
'plan',
|
|
11
|
+
'execute',
|
|
12
|
+
'answer',
|
|
13
|
+
'config',
|
|
14
|
+
'validate',
|
|
15
|
+
'introspect',
|
|
16
|
+
]);
|
|
17
|
+
/**
|
|
18
|
+
* Validate filename follows kebab-case pattern
|
|
19
|
+
* Valid: deploy-app.md, build-project-2.md, copy-files.md
|
|
20
|
+
* Invalid: Deploy_App.md, buildProject.md, DEPLOY.md, file name.md
|
|
21
|
+
*/
|
|
22
|
+
export function isValidSkillFilename(filename) {
|
|
23
|
+
// Must end with .md or .MD extension
|
|
24
|
+
if (!filename.endsWith('.md') && !filename.endsWith('.MD')) {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
// Extract name without extension
|
|
28
|
+
const name = filename.slice(0, -3);
|
|
29
|
+
// Must match kebab-case pattern: lowercase letters, numbers, and hyphens only
|
|
30
|
+
// Must start with a letter, and not start or end with a hyphen
|
|
31
|
+
const kebabCasePattern = /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/;
|
|
32
|
+
return kebabCasePattern.test(name);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Check if skill key conflicts with built-in skills
|
|
36
|
+
*/
|
|
37
|
+
export function conflictsWithBuiltIn(key) {
|
|
38
|
+
return BUILT_IN_SKILLS.has(key);
|
|
39
|
+
}
|
|
5
40
|
/**
|
|
6
41
|
* Get the path to the skills directory
|
|
7
42
|
*/
|
|
@@ -10,7 +45,8 @@ export function getSkillsDirectory() {
|
|
|
10
45
|
}
|
|
11
46
|
/**
|
|
12
47
|
* Load all skill markdown files from the skills directory
|
|
13
|
-
* Returns an array of
|
|
48
|
+
* Returns an array of objects with filename (key) and content
|
|
49
|
+
* Filters out invalid filenames and conflicts with built-in skills
|
|
14
50
|
*/
|
|
15
51
|
export function loadSkills() {
|
|
16
52
|
const skillsDir = getSkillsDirectory();
|
|
@@ -20,12 +56,27 @@ export function loadSkills() {
|
|
|
20
56
|
}
|
|
21
57
|
try {
|
|
22
58
|
const files = readdirSync(skillsDir);
|
|
23
|
-
// Filter
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
59
|
+
// Filter and map valid skill files
|
|
60
|
+
return files
|
|
61
|
+
.filter((file) => {
|
|
62
|
+
// Must follow kebab-case naming convention
|
|
63
|
+
if (!isValidSkillFilename(file)) {
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
// Extract key (filename without extension, handles both .md and .MD)
|
|
67
|
+
const key = file.slice(0, -3);
|
|
68
|
+
// Must not conflict with built-in skills
|
|
69
|
+
if (conflictsWithBuiltIn(key)) {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
return true;
|
|
73
|
+
})
|
|
74
|
+
.map((file) => {
|
|
75
|
+
// Extract key (filename without extension, handles both .md and .MD)
|
|
76
|
+
const key = file.slice(0, -3);
|
|
27
77
|
const filePath = join(skillsDir, file);
|
|
28
|
-
|
|
78
|
+
const content = readFileSync(filePath, 'utf-8');
|
|
79
|
+
return { key, content };
|
|
29
80
|
});
|
|
30
81
|
}
|
|
31
82
|
catch {
|
|
@@ -38,17 +89,17 @@ export function loadSkills() {
|
|
|
38
89
|
* Returns structured skill definitions (including invalid skills)
|
|
39
90
|
*/
|
|
40
91
|
export function loadSkillDefinitions() {
|
|
41
|
-
const
|
|
42
|
-
return
|
|
92
|
+
const skills = loadSkills();
|
|
93
|
+
return skills.map(({ key, content }) => parseSkillMarkdown(key, content));
|
|
43
94
|
}
|
|
44
95
|
/**
|
|
45
96
|
* Load skills and mark incomplete ones in their markdown
|
|
46
97
|
* Returns array of skill markdown with status markers
|
|
47
98
|
*/
|
|
48
99
|
export function loadSkillsWithValidation() {
|
|
49
|
-
const
|
|
50
|
-
return
|
|
51
|
-
const parsed = parseSkillMarkdown(content);
|
|
100
|
+
const skills = loadSkills();
|
|
101
|
+
return skills.map(({ key, content }) => {
|
|
102
|
+
const parsed = parseSkillMarkdown(key, content);
|
|
52
103
|
// If skill is incomplete (either validation failed or needs more documentation), append (INCOMPLETE) to the name
|
|
53
104
|
if (parsed.isIncomplete) {
|
|
54
105
|
return content.replace(/^(#{1,6}\s+Name\s*\n+)(.+?)(\n|$)/im, `$1$2 (INCOMPLETE)$3`);
|
|
@@ -58,13 +109,19 @@ export function loadSkillsWithValidation() {
|
|
|
58
109
|
}
|
|
59
110
|
/**
|
|
60
111
|
* Create skill lookup function from definitions
|
|
112
|
+
* Lookup by key (display name is converted to kebab-case for matching)
|
|
113
|
+
* Example: "Deploy App" -> "deploy-app" -> matches skill with key "deploy-app"
|
|
61
114
|
*/
|
|
62
115
|
export function createSkillLookup(definitions) {
|
|
63
|
-
const
|
|
116
|
+
const keyMap = new Map();
|
|
64
117
|
for (const definition of definitions) {
|
|
65
|
-
|
|
118
|
+
keyMap.set(definition.key, definition);
|
|
66
119
|
}
|
|
67
|
-
return (name) =>
|
|
120
|
+
return (name) => {
|
|
121
|
+
// Convert display name to kebab-case key for lookup
|
|
122
|
+
const key = displayNameToKey(name);
|
|
123
|
+
return keyMap.get(key) || null;
|
|
124
|
+
};
|
|
68
125
|
}
|
|
69
126
|
/**
|
|
70
127
|
* Format skills for inclusion in the planning prompt
|
|
@@ -74,7 +131,6 @@ export function formatSkillsForPrompt(skills) {
|
|
|
74
131
|
return '';
|
|
75
132
|
}
|
|
76
133
|
const header = `
|
|
77
|
-
|
|
78
134
|
## Available Skills
|
|
79
135
|
|
|
80
136
|
The following skills define domain-specific workflows. When the user's
|
|
@@ -90,6 +146,98 @@ brackets for additional information. Use commas instead. For example:
|
|
|
90
146
|
- WRONG: "Build project Alpha (the legacy version)"
|
|
91
147
|
|
|
92
148
|
`;
|
|
93
|
-
const skillsContent = skills.join('\n\n');
|
|
149
|
+
const skillsContent = skills.map((s) => s.trim()).join('\n\n');
|
|
94
150
|
return header + skillsContent;
|
|
95
151
|
}
|
|
152
|
+
/**
|
|
153
|
+
* Parse skill reference from execution line
|
|
154
|
+
* Format: [ Display Name ] with mandatory spaces
|
|
155
|
+
* Returns display name if line matches format, otherwise null
|
|
156
|
+
* Example: "[ My Skill ]" -> "My Skill"
|
|
157
|
+
*/
|
|
158
|
+
export function parseSkillReference(line) {
|
|
159
|
+
// Must match format: [ content ] with at least one space before and after
|
|
160
|
+
const match = line.trim().match(/^\[\s+(.+?)\s+\]$/);
|
|
161
|
+
return match ? match[1] : null;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Check if execution line is a skill reference
|
|
165
|
+
* Must have format: [ content ] with spaces
|
|
166
|
+
*/
|
|
167
|
+
export function isSkillReference(line) {
|
|
168
|
+
return /^\[\s+.+?\s+\]$/.test(line.trim());
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Expand skill references in execution commands
|
|
172
|
+
* Returns expanded execution lines with references replaced
|
|
173
|
+
* Throws error if circular reference detected or skill not found
|
|
174
|
+
* Reference format: [ Skill Name ]
|
|
175
|
+
*/
|
|
176
|
+
export function expandSkillReferences(execution, skillLookup, visited = new Set()) {
|
|
177
|
+
const expanded = [];
|
|
178
|
+
for (const line of execution) {
|
|
179
|
+
// First: Detect if line matches [ XXX ] format
|
|
180
|
+
const skillName = parseSkillReference(line);
|
|
181
|
+
if (!skillName) {
|
|
182
|
+
// Not a reference, keep command as-is
|
|
183
|
+
expanded.push(line);
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
186
|
+
// Check for circular reference
|
|
187
|
+
if (visited.has(skillName)) {
|
|
188
|
+
throw new Error(`Circular skill reference detected: ${Array.from(visited).join(' → ')} → ${skillName}`);
|
|
189
|
+
}
|
|
190
|
+
// Second: Match against skill name
|
|
191
|
+
const skill = skillLookup(skillName);
|
|
192
|
+
if (!skill) {
|
|
193
|
+
// Referenced skill not found - throw error to break execution
|
|
194
|
+
throw new Error(getUnknownSkillMessage(skillName));
|
|
195
|
+
}
|
|
196
|
+
// Recursively expand referenced skill's execution
|
|
197
|
+
const newVisited = new Set(visited);
|
|
198
|
+
newVisited.add(skillName);
|
|
199
|
+
const referencedExecution = expandSkillReferences(skill.execution, skillLookup, newVisited);
|
|
200
|
+
expanded.push(...referencedExecution);
|
|
201
|
+
}
|
|
202
|
+
return expanded;
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Get all skill names referenced in execution (including nested)
|
|
206
|
+
* Returns unique set of skill names
|
|
207
|
+
*/
|
|
208
|
+
export function getReferencedSkills(execution, skillLookup, visited = new Set()) {
|
|
209
|
+
const referenced = new Set();
|
|
210
|
+
for (const line of execution) {
|
|
211
|
+
const skillName = parseSkillReference(line);
|
|
212
|
+
if (!skillName || visited.has(skillName)) {
|
|
213
|
+
continue;
|
|
214
|
+
}
|
|
215
|
+
referenced.add(skillName);
|
|
216
|
+
const skill = skillLookup(skillName);
|
|
217
|
+
if (skill) {
|
|
218
|
+
const newVisited = new Set(visited);
|
|
219
|
+
newVisited.add(skillName);
|
|
220
|
+
const nested = getReferencedSkills(skill.execution, skillLookup, newVisited);
|
|
221
|
+
for (const name of nested) {
|
|
222
|
+
referenced.add(name);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
return referenced;
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Validate skill references don't form cycles
|
|
230
|
+
* Returns true if valid, false if circular reference detected
|
|
231
|
+
*/
|
|
232
|
+
export function validateNoCycles(execution, skillLookup, visited = new Set()) {
|
|
233
|
+
try {
|
|
234
|
+
expandSkillReferences(execution, skillLookup, visited);
|
|
235
|
+
return true;
|
|
236
|
+
}
|
|
237
|
+
catch (error) {
|
|
238
|
+
if (error instanceof Error && error.message.includes('Circular')) {
|
|
239
|
+
return false;
|
|
240
|
+
}
|
|
241
|
+
throw error;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import { extractPlaceholders, pathToString, resolveVariant, } from './
|
|
2
|
-
import { loadUserConfig, hasConfigPath } from './
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { getConfigType, parseSkillMarkdown } from './skill-parser.js';
|
|
1
|
+
import { extractPlaceholders, pathToString, resolveVariant, } from './resolver.js';
|
|
2
|
+
import { loadUserConfig, hasConfigPath } from './loader.js';
|
|
3
|
+
import { loadSkillDefinitions, createSkillLookup, expandSkillReferences, } from './skills.js';
|
|
4
|
+
import { getConfigType } from './parser.js';
|
|
6
5
|
/**
|
|
7
6
|
* Validate config requirements for execute tasks
|
|
8
7
|
* Returns validation result with missing config and validation errors
|
|
@@ -14,9 +13,8 @@ export function validateExecuteTasks(tasks) {
|
|
|
14
13
|
const validationErrors = [];
|
|
15
14
|
const seenSkills = new Set();
|
|
16
15
|
// Load all skills (including invalid ones for validation)
|
|
17
|
-
const
|
|
18
|
-
const
|
|
19
|
-
const skillLookup = (name) => parsedSkills.find((s) => s.name === name) || null;
|
|
16
|
+
const parsedSkills = loadSkillDefinitions();
|
|
17
|
+
const skillLookup = createSkillLookup(parsedSkills);
|
|
20
18
|
// Check for invalid skills being used in tasks
|
|
21
19
|
for (const task of tasks) {
|
|
22
20
|
const skillName = typeof task.params?.skill === 'string' ? task.params.skill : null;
|
|
@@ -5,9 +5,9 @@ command-line concierge. Your role is to **answer questions** and provide
|
|
|
5
5
|
up-to-date information when a task with type "answer" has been planned and
|
|
6
6
|
confirmed.
|
|
7
7
|
|
|
8
|
-
**IMPORTANT**: Use web search to find current, accurate information. This
|
|
9
|
-
is designed for quick answers from the terminal without needing to open a
|
|
10
|
-
browser. Always search for the latest data rather than relying solely on
|
|
8
|
+
**IMPORTANT**: Use web search to find current, accurate information. This
|
|
9
|
+
tool is designed for quick answers from the terminal without needing to open a
|
|
10
|
+
web browser. Always search for the latest data rather than relying solely on
|
|
11
11
|
training data.
|
|
12
12
|
|
|
13
13
|
## Execution Flow
|
|
@@ -60,11 +60,11 @@ TypeScript code compiles to JavaScript and runs anywhere JavaScript runs.
|
|
|
60
60
|
|
|
61
61
|
Bad answer (too verbose):
|
|
62
62
|
```
|
|
63
|
-
TypeScript is a strongly typed programming language that builds on
|
|
64
|
-
giving you better tooling at any scale. TypeScript adds
|
|
65
|
-
JavaScript to support a tighter integration with your
|
|
66
|
-
early in development by checking types. TypeScript
|
|
67
|
-
which runs anywhere.
|
|
63
|
+
TypeScript is a strongly typed programming language that builds on
|
|
64
|
+
JavaScript, giving you better tooling at any scale. TypeScript adds
|
|
65
|
+
additional syntax to JavaScript to support a tighter integration with your
|
|
66
|
+
editor. It catches errors early in development by checking types. TypeScript
|
|
67
|
+
code converts to JavaScript which runs anywhere.
|
|
68
68
|
```
|
|
69
69
|
|
|
70
70
|
### Example 2: Technical explanation
|
|
@@ -101,7 +101,8 @@ They enable cleaner, more reusable component logic.
|
|
|
101
101
|
|
|
102
102
|
## Guidelines
|
|
103
103
|
|
|
104
|
-
1. **Be direct**: Answer the question immediately, don't introduce your
|
|
104
|
+
1. **Be direct**: Answer the question immediately, don't introduce your
|
|
105
|
+
answer
|
|
105
106
|
2. **Be accurate**: Provide correct, factual information
|
|
106
107
|
3. **Be concise**: Respect the 4-line, 80-character constraints strictly
|
|
107
108
|
4. **Be helpful**: Focus on what the user needs to know
|
|
@@ -1,33 +1,40 @@
|
|
|
1
1
|
## Overview
|
|
2
2
|
|
|
3
|
-
You are the CONFIG tool for "pls" (please), a professional command-line
|
|
4
|
-
Your role is to determine which configuration settings the user
|
|
5
|
-
based on their query.
|
|
3
|
+
You are the CONFIG tool for "pls" (please), a professional command-line
|
|
4
|
+
concierge. Your role is to determine which configuration settings the user
|
|
5
|
+
wants to configure based on their query.
|
|
6
6
|
|
|
7
7
|
## Input
|
|
8
8
|
|
|
9
9
|
You will receive:
|
|
10
|
-
- `configStructure`: Object mapping config keys to descriptions (e.g.,
|
|
11
|
-
|
|
10
|
+
- `configStructure`: Object mapping config keys to descriptions (e.g.,
|
|
11
|
+
{"anthropic.key": "Anthropic API key", "settings.debug": "Debug mode
|
|
12
|
+
(optional)"})
|
|
13
|
+
- `configuredKeys`: Array of keys that exist in the user's config file
|
|
14
|
+
(e.g., ["anthropic.key", "anthropic.model", "settings.debug"])
|
|
12
15
|
- `query`: User's request (e.g., "app", "mode", "anthropic", or empty)
|
|
13
16
|
|
|
14
17
|
## Task
|
|
15
18
|
|
|
16
|
-
Determine which config keys the user wants to configure and return them
|
|
19
|
+
Determine which config keys the user wants to configure and return them
|
|
20
|
+
as tasks.
|
|
17
21
|
|
|
18
22
|
## Mapping Rules
|
|
19
23
|
|
|
20
24
|
### Query: "app" or empty/unclear
|
|
21
25
|
- Return all **required** config keys (those needed for the app to work)
|
|
22
|
-
- Also include any keys marked as "(optional)" that appear in
|
|
23
|
-
|
|
26
|
+
- Also include any keys marked as "(optional)" that appear in
|
|
27
|
+
`configuredKeys` (optional settings that exist in user's config file)
|
|
28
|
+
- Also include any keys marked as "(discovered)" (they exist in user's
|
|
29
|
+
config file but aren't in schema)
|
|
24
30
|
- Required keys: `anthropic.key`, `anthropic.model`
|
|
25
31
|
|
|
26
32
|
### Query: "mode"
|
|
27
33
|
- Return only: `settings.debug`
|
|
28
34
|
|
|
29
35
|
### Query: "anthropic"
|
|
30
|
-
- Return all keys starting with `anthropic.` (usually `anthropic.key` and
|
|
36
|
+
- Return all keys starting with `anthropic.` (usually `anthropic.key` and
|
|
37
|
+
`anthropic.model`)
|
|
31
38
|
|
|
32
39
|
### Other queries
|
|
33
40
|
- Match the query against config key names and descriptions
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
## Overview
|
|
2
2
|
|
|
3
|
-
You are the execution component of "pls" (please), a professional
|
|
4
|
-
concierge. Your role is to **execute shell commands** and
|
|
5
|
-
with type "execute" have been planned and confirmed.
|
|
3
|
+
You are the execution component of "pls" (please), a professional
|
|
4
|
+
command-line concierge. Your role is to **execute shell commands** and
|
|
5
|
+
operations when tasks with type "execute" have been planned and confirmed.
|
|
6
6
|
|
|
7
7
|
## Execution Flow
|
|
8
8
|
|
|
@@ -11,23 +11,23 @@ This tool is invoked AFTER:
|
|
|
11
11
|
2. User reviewed and confirmed the plan
|
|
12
12
|
3. The execute tasks are now being executed
|
|
13
13
|
|
|
14
|
-
Your task is to translate the planned actions into specific shell commands
|
|
15
|
-
can be run in the terminal.
|
|
14
|
+
Your task is to translate the planned actions into specific shell commands
|
|
15
|
+
that can be run in the terminal.
|
|
16
16
|
|
|
17
17
|
## Input
|
|
18
18
|
|
|
19
19
|
You will receive:
|
|
20
20
|
- An array of tasks with their actions and parameters
|
|
21
|
-
- Each task describes what needs to be done (e.g., "Create a new file
|
|
22
|
-
test.txt", "List files in the current directory")
|
|
21
|
+
- Each task describes what needs to be done (e.g., "Create a new file
|
|
22
|
+
called test.txt", "List files in the current directory")
|
|
23
23
|
- Tasks may include params with specific values (paths, filenames, etc.)
|
|
24
|
-
- Tasks from user-defined skills include params.skill (skill name) and
|
|
25
|
-
values that were substituted into the action
|
|
24
|
+
- Tasks from user-defined skills include params.skill (skill name) and
|
|
25
|
+
parameter values that were substituted into the action
|
|
26
26
|
|
|
27
27
|
## Skill-Based Command Generation
|
|
28
28
|
|
|
29
|
-
**CRITICAL**: When tasks originate from a user-defined skill, you MUST use
|
|
30
|
-
skill's **Execution** section to generate commands, NOT invent your own.
|
|
29
|
+
**CRITICAL**: When tasks originate from a user-defined skill, you MUST use
|
|
30
|
+
the skill's **Execution** section to generate commands, NOT invent your own.
|
|
31
31
|
|
|
32
32
|
### Understanding Skill Structure
|
|
33
33
|
|
|
@@ -35,16 +35,18 @@ User-defined skills have two key sections:
|
|
|
35
35
|
- **Steps**: Describes WHAT to do (shown to user as task actions)
|
|
36
36
|
- **Execution**: Describes HOW to do it (actual shell commands)
|
|
37
37
|
|
|
38
|
-
Each line in Steps corresponds to a line in Execution at the same
|
|
38
|
+
Each line in Steps corresponds to a line in Execution at the same
|
|
39
|
+
position.
|
|
39
40
|
|
|
40
41
|
### How to Generate Commands from Skills
|
|
41
42
|
|
|
42
43
|
1. **Identify skill tasks**: Check if tasks have params.skill
|
|
43
|
-
2. **Find the skill**: Look up the skill in "Available Skills" section
|
|
44
|
+
2. **Find the skill**: Look up the skill in "Available Skills" section
|
|
45
|
+
below
|
|
44
46
|
3. **Match tasks to Execution**: Each task action came from a Steps line;
|
|
45
47
|
use the corresponding Execution line for the command
|
|
46
|
-
4. **Substitute parameters**: Replace {PARAM} placeholders with actual
|
|
47
|
-
from task params
|
|
48
|
+
4. **Substitute parameters**: Replace {PARAM} placeholders with actual
|
|
49
|
+
values from task params
|
|
48
50
|
|
|
49
51
|
### Example Skill
|
|
50
52
|
|
|
@@ -59,8 +61,8 @@ Process Data
|
|
|
59
61
|
|
|
60
62
|
### Execution
|
|
61
63
|
- curl -O https://data.example.com/{SOURCE}.csv
|
|
62
|
-
- python3 transform.py --input {SOURCE}.csv --output
|
|
63
|
-
- csvtool col 1-3
|
|
64
|
+
- python3 transform.py --input {SOURCE}.csv --output data.csv
|
|
65
|
+
- csvtool col 1-3 data.csv > output.{FORMAT}
|
|
64
66
|
```
|
|
65
67
|
|
|
66
68
|
### Matching Process
|
|
@@ -77,9 +79,9 @@ Given tasks from this skill:
|
|
|
77
79
|
Do NOT invent different commands - use exactly what the skill specifies,
|
|
78
80
|
with parameter placeholders replaced by actual values.
|
|
79
81
|
|
|
80
|
-
**CRITICAL**: Take the exact command from the ### Execution section. Do
|
|
81
|
-
modify, improve, or rewrite the command in any way. The user wrote
|
|
82
|
-
commands specifically for their environment and workflow.
|
|
82
|
+
**CRITICAL**: Take the exact command from the ### Execution section. Do
|
|
83
|
+
not modify, improve, or rewrite the command in any way. The user wrote
|
|
84
|
+
these commands specifically for their environment and workflow.
|
|
83
85
|
|
|
84
86
|
## Response Format
|
|
85
87
|
|
|
@@ -90,9 +92,11 @@ Return a structured response with commands to execute:
|
|
|
90
92
|
- **commands**: Array of command objects to execute sequentially
|
|
91
93
|
|
|
92
94
|
**Command object structure:**
|
|
93
|
-
- **description**: Brief description of what this command does (max 64
|
|
95
|
+
- **description**: Brief description of what this command does (max 64
|
|
96
|
+
chars)
|
|
94
97
|
- **command**: The exact shell command to run
|
|
95
|
-
- **workdir**: Optional working directory for the command (defaults to
|
|
98
|
+
- **workdir**: Optional working directory for the command (defaults to
|
|
99
|
+
current)
|
|
96
100
|
- **timeout**: Optional timeout in milliseconds (defaults to 30000)
|
|
97
101
|
- **critical**: Whether failure should stop execution (defaults to true)
|
|
98
102
|
|
|
@@ -101,24 +105,31 @@ Return a structured response with commands to execute:
|
|
|
101
105
|
When generating commands:
|
|
102
106
|
|
|
103
107
|
1. **Be precise**: Generate exact, runnable shell commands
|
|
104
|
-
2. **Be safe**: Never generate destructive commands without explicit user
|
|
105
|
-
|
|
108
|
+
2. **Be safe**: Never generate destructive commands without explicit user
|
|
109
|
+
intent
|
|
110
|
+
3. **Use parameters**: Extract values from task params and incorporate
|
|
111
|
+
them
|
|
106
112
|
4. **Handle paths**: Use proper quoting for paths with spaces
|
|
107
113
|
5. **Be portable**: Prefer POSIX-compatible commands when possible
|
|
108
114
|
|
|
109
115
|
**Safety rules:**
|
|
110
116
|
- NEVER run `rm -rf /` or any command that could delete system files
|
|
111
|
-
- NEVER run commands that modify system configuration without explicit
|
|
117
|
+
- NEVER run commands that modify system configuration without explicit
|
|
118
|
+
request
|
|
112
119
|
- NEVER expose sensitive information in command output
|
|
113
|
-
- Always use safe defaults (e.g., prefer `rm -i` over `rm -f` for
|
|
120
|
+
- Always use safe defaults (e.g., prefer `rm -i` over `rm -f` for
|
|
121
|
+
deletions)
|
|
114
122
|
- For file deletions, prefer moving to trash over permanent deletion
|
|
115
123
|
|
|
116
124
|
## Examples
|
|
117
125
|
|
|
118
126
|
### Example 1: Simple file creation
|
|
119
127
|
|
|
120
|
-
Task: {
|
|
121
|
-
|
|
128
|
+
Task: {
|
|
129
|
+
action: "Create a new file called test.txt",
|
|
130
|
+
type: "execute",
|
|
131
|
+
params: { filename: "test.txt" }
|
|
132
|
+
}
|
|
122
133
|
|
|
123
134
|
Response:
|
|
124
135
|
```
|
|
@@ -130,7 +141,10 @@ commands:
|
|
|
130
141
|
|
|
131
142
|
### Example 2: Directory listing
|
|
132
143
|
|
|
133
|
-
Task: {
|
|
144
|
+
Task: {
|
|
145
|
+
action: "Show files in the current directory",
|
|
146
|
+
type: "execute"
|
|
147
|
+
}
|
|
134
148
|
|
|
135
149
|
Response:
|
|
136
150
|
```
|
|
@@ -143,8 +157,11 @@ commands:
|
|
|
143
157
|
### Example 3: Multiple sequential commands
|
|
144
158
|
|
|
145
159
|
Tasks:
|
|
146
|
-
- {
|
|
147
|
-
|
|
160
|
+
- {
|
|
161
|
+
action: "Create project directory",
|
|
162
|
+
type: "execute",
|
|
163
|
+
params: { path: "my-project" }
|
|
164
|
+
}
|
|
148
165
|
- { action: "Initialize git repository", type: "execute" }
|
|
149
166
|
- { action: "Create README file", type: "execute" }
|
|
150
167
|
|
|
@@ -164,7 +181,10 @@ commands:
|
|
|
164
181
|
|
|
165
182
|
### Example 4: Install dependencies
|
|
166
183
|
|
|
167
|
-
Task: {
|
|
184
|
+
Task: {
|
|
185
|
+
action: "Install dependencies",
|
|
186
|
+
type: "execute"
|
|
187
|
+
}
|
|
168
188
|
|
|
169
189
|
Response:
|
|
170
190
|
```
|
|
@@ -177,20 +197,30 @@ commands:
|
|
|
177
197
|
|
|
178
198
|
### Example 5: Skill-based execution
|
|
179
199
|
|
|
180
|
-
When executing from a skill like "Process Data", tasks include
|
|
200
|
+
When executing from a skill like "Process Data", tasks include
|
|
201
|
+
params.skill:
|
|
181
202
|
|
|
182
203
|
Tasks:
|
|
183
|
-
- {
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
params: { skill: "Process Data", source: "sales", format: "json" }
|
|
187
|
-
|
|
188
|
-
|
|
204
|
+
- {
|
|
205
|
+
action: "Load the sales dataset",
|
|
206
|
+
type: "execute",
|
|
207
|
+
params: { skill: "Process Data", source: "sales", format: "json" }
|
|
208
|
+
}
|
|
209
|
+
- {
|
|
210
|
+
action: "Transform the sales data",
|
|
211
|
+
type: "execute",
|
|
212
|
+
params: { skill: "Process Data", source: "sales", format: "json" }
|
|
213
|
+
}
|
|
214
|
+
- {
|
|
215
|
+
action: "Export the results to json",
|
|
216
|
+
type: "execute",
|
|
217
|
+
params: { skill: "Process Data", source: "sales", format: "json" }
|
|
218
|
+
}
|
|
189
219
|
|
|
190
220
|
The "Process Data" skill's Execution section specifies:
|
|
191
221
|
- Line 1: curl -O https://data.example.com/{SOURCE}.csv
|
|
192
|
-
- Line 2: python3 transform.py --input {SOURCE}.csv --output
|
|
193
|
-
- Line 3: csvtool col 1-3
|
|
222
|
+
- Line 2: python3 transform.py --input {SOURCE}.csv --output data.csv
|
|
223
|
+
- Line 3: csvtool col 1-3 data.csv > output.{FORMAT}
|
|
194
224
|
|
|
195
225
|
Response (using skill's Execution commands):
|
|
196
226
|
```
|
|
@@ -200,19 +230,23 @@ commands:
|
|
|
200
230
|
command: "curl -O https://data.example.com/sales.csv"
|
|
201
231
|
timeout: 60000
|
|
202
232
|
- description: "Transform the sales data"
|
|
203
|
-
command: "python3 transform.py --input sales.csv --output
|
|
233
|
+
command: "python3 transform.py --input sales.csv --output data.csv"
|
|
204
234
|
timeout: 120000
|
|
205
235
|
- description: "Export the results to json"
|
|
206
|
-
command: "csvtool col 1-3
|
|
236
|
+
command: "csvtool col 1-3 data.csv > output.json"
|
|
207
237
|
```
|
|
208
238
|
|
|
209
|
-
Note: Commands come directly from the skill's Execution section, with
|
|
210
|
-
replaced by "sales" and {FORMAT} replaced by "json" from task
|
|
239
|
+
Note: Commands come directly from the skill's Execution section, with
|
|
240
|
+
{SOURCE} replaced by "sales" and {FORMAT} replaced by "json" from task
|
|
241
|
+
params.
|
|
211
242
|
|
|
212
243
|
### Example 6: File operations with paths
|
|
213
244
|
|
|
214
|
-
Task: {
|
|
215
|
-
|
|
245
|
+
Task: {
|
|
246
|
+
action: "Copy config to backup",
|
|
247
|
+
type: "execute",
|
|
248
|
+
params: { source: "~/.config/app", destination: "~/.config/app.backup" }
|
|
249
|
+
}
|
|
216
250
|
|
|
217
251
|
Response:
|
|
218
252
|
```
|
|
@@ -224,7 +258,10 @@ commands:
|
|
|
224
258
|
|
|
225
259
|
### Example 7: Checking system information
|
|
226
260
|
|
|
227
|
-
Task: {
|
|
261
|
+
Task: {
|
|
262
|
+
action: "Check disk space",
|
|
263
|
+
type: "execute"
|
|
264
|
+
}
|
|
228
265
|
|
|
229
266
|
Response:
|
|
230
267
|
```
|
|
@@ -240,11 +277,12 @@ For complex multi-step operations:
|
|
|
240
277
|
|
|
241
278
|
1. **Sequential dependencies**: Mark early commands as critical so failure
|
|
242
279
|
stops the chain
|
|
243
|
-
2. **Long-running processes**: Set appropriate timeouts (build processes
|
|
244
|
-
need 10+ minutes)
|
|
245
|
-
3. **Working directories**: Use workdir to ensure commands run in the
|
|
246
|
-
location
|
|
247
|
-
4. **Error handling**: For non-critical cleanup steps, set critical:
|
|
280
|
+
2. **Long-running processes**: Set appropriate timeouts (build processes
|
|
281
|
+
may need 10+ minutes)
|
|
282
|
+
3. **Working directories**: Use workdir to ensure commands run in the
|
|
283
|
+
right location
|
|
284
|
+
4. **Error handling**: For non-critical cleanup steps, set critical:
|
|
285
|
+
false
|
|
248
286
|
|
|
249
287
|
## Common Mistakes to Avoid
|
|
250
288
|
|