prompt-language-shell 0.8.0 → 0.8.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.
@@ -6,6 +6,10 @@ import { Palette } from './colors.js';
6
6
  * Logs information based on the current debug level setting
7
7
  */
8
8
  let currentDebugLevel = DebugLevel.None;
9
+ /**
10
+ * Accumulated warnings to be displayed in the timeline
11
+ */
12
+ const warnings = [];
9
13
  /**
10
14
  * Initialize the logger with the current debug level from config
11
15
  */
@@ -24,6 +28,26 @@ export function setDebugLevel(debug) {
24
28
  export function getDebugLevel() {
25
29
  return currentDebugLevel;
26
30
  }
31
+ /**
32
+ * Store a warning message to be displayed in the timeline
33
+ * Only stores warnings at Info or Verbose debug levels
34
+ */
35
+ export function displayWarning(message, error) {
36
+ if (currentDebugLevel === DebugLevel.None) {
37
+ return;
38
+ }
39
+ const errorDetails = error instanceof Error ? `: ${error.message}` : '';
40
+ warnings.push(`${message}${errorDetails}`);
41
+ }
42
+ /**
43
+ * Get all accumulated warnings and clear the list
44
+ * Returns array of warning messages
45
+ */
46
+ export function getWarnings() {
47
+ const result = [...warnings];
48
+ warnings.length = 0;
49
+ return result;
50
+ }
27
51
  /**
28
52
  * Create debug component for system prompts sent to the LLM
29
53
  * Only creates at Verbose level
@@ -1,4 +1,5 @@
1
1
  import YAML from 'yaml';
2
+ import { displayWarning } from './logger.js';
2
3
  /**
3
4
  * Validate a skill without parsing it fully
4
5
  * Returns validation error if skill is invalid, null if valid
@@ -188,7 +189,8 @@ function parseConfigSchema(content) {
188
189
  }
189
190
  return parsed;
190
191
  }
191
- catch {
192
+ catch (error) {
193
+ displayWarning('Failed to parse config schema in skill', error);
192
194
  return undefined;
193
195
  }
194
196
  }
@@ -5,12 +5,12 @@ import { routeTasksWithConfirm } from './router.js';
5
5
  * Handle refinement flow for DEFINE tasks
6
6
  * Called when user selects options from a plan with DEFINE tasks
7
7
  */
8
- export async function handleRefinement(selectedTasks, service, originalCommand, handlers) {
8
+ export async function handleRefinement(selectedTasks, service, originalCommand, queueHandlers, lifecycleHandlers, workflowHandlers, errorHandlers) {
9
9
  // Create and add refinement component to queue
10
10
  const refinementDef = createRefinement(getRefiningMessage(), (operation) => {
11
- handlers.onAborted(operation);
11
+ errorHandlers.onAborted(operation);
12
12
  });
13
- handlers.addToQueue(refinementDef);
13
+ queueHandlers.addToQueue(refinementDef);
14
14
  try {
15
15
  // Build refined command from selected tasks
16
16
  const refinedCommand = selectedTasks
@@ -23,18 +23,18 @@ export async function handleRefinement(selectedTasks, service, originalCommand,
23
23
  // Call LLM to refine plan with selected tasks
24
24
  const refinedResult = await service.processWithTool(refinedCommand, 'schedule');
25
25
  // Complete the Refinement component
26
- handlers.completeActive();
26
+ lifecycleHandlers.completeActive();
27
27
  // Add debug components to timeline if present
28
- if (refinedResult.debug && refinedResult.debug.length > 0) {
29
- handlers.addToTimeline(...refinedResult.debug);
28
+ if (refinedResult.debug?.length) {
29
+ workflowHandlers.addToTimeline(...refinedResult.debug);
30
30
  }
31
31
  // Route refined tasks to appropriate components
32
- routeTasksWithConfirm(refinedResult.tasks, refinedResult.message, service, originalCommand, handlers, false // No DEFINE tasks in refined result
32
+ routeTasksWithConfirm(refinedResult.tasks, refinedResult.message, service, originalCommand, queueHandlers, workflowHandlers, errorHandlers, false // No DEFINE tasks in refined result
33
33
  );
34
34
  }
35
35
  catch (err) {
36
- handlers.completeActive();
36
+ lifecycleHandlers.completeActive();
37
37
  const errorMessage = formatErrorMessage(err);
38
- handlers.onError(errorMessage);
38
+ errorHandlers.onError(errorMessage);
39
39
  }
40
40
  }
@@ -32,7 +32,7 @@ class ToolRegistry {
32
32
  }
33
33
  // Create singleton instance
34
34
  export const toolRegistry = new ToolRegistry();
35
- // Register built-in tools
35
+ // Register system tools
36
36
  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';
@@ -1,3 +1,4 @@
1
+ import { asScheduledTasks } from '../types/guards.js';
1
2
  import { FeedbackType, TaskType } from '../types/types.js';
2
3
  import { createAnswerDefinition, createConfigDefinitionWithKeys, createConfirmDefinition, createExecuteDefinition, createFeedback, createIntrospectDefinition, createMessage, createScheduleDefinition, createValidateDefinition, } from './components.js';
3
4
  import { saveConfig, unflattenConfig } from './configuration.js';
@@ -19,7 +20,7 @@ export function getOperationName(tasks) {
19
20
  * Route tasks to appropriate components with Confirm flow
20
21
  * Handles the complete flow: Plan → Confirm → Execute/Answer/Introspect
21
22
  */
22
- export function routeTasksWithConfirm(tasks, message, service, userRequest, handlers, hasDefineTask = false) {
23
+ export function routeTasksWithConfirm(tasks, message, service, userRequest, queueHandlers, workflowHandlers, errorHandlers, hasDefineTask = false) {
23
24
  if (tasks.length === 0)
24
25
  return;
25
26
  // Filter out ignore and discard tasks early
@@ -27,7 +28,7 @@ export function routeTasksWithConfirm(tasks, message, service, userRequest, hand
27
28
  // Check if no valid tasks remain after filtering
28
29
  if (validTasks.length === 0) {
29
30
  const message = createMessage(getUnknownRequestMessage());
30
- handlers.addToQueue(message);
31
+ queueHandlers.addToQueue(message);
31
32
  return;
32
33
  }
33
34
  const operation = getOperationName(validTasks);
@@ -35,7 +36,7 @@ export function routeTasksWithConfirm(tasks, message, service, userRequest, hand
35
36
  // Has DEFINE tasks - add Schedule to queue for user selection
36
37
  // Refinement flow will call this function again with refined tasks
37
38
  const scheduleDefinition = createScheduleDefinition(message, validTasks);
38
- handlers.addToQueue(scheduleDefinition);
39
+ queueHandlers.addToQueue(scheduleDefinition);
39
40
  }
40
41
  else {
41
42
  // No DEFINE tasks - Schedule auto-completes and adds Confirm to queue
@@ -46,17 +47,17 @@ export function routeTasksWithConfirm(tasks, message, service, userRequest, hand
46
47
  // Schedule completed - add Confirm to queue
47
48
  const confirmDefinition = createConfirmDefinition(() => {
48
49
  // User confirmed - complete both Confirm and Schedule, then route to appropriate component
49
- handlers.completeActiveAndPending();
50
- executeTasksAfterConfirm(validTasks, service, userRequest, handlers);
50
+ workflowHandlers.completeActiveAndPending();
51
+ executeTasksAfterConfirm(validTasks, service, userRequest, queueHandlers, errorHandlers);
51
52
  }, () => {
52
53
  // User cancelled - complete both Confirm and Schedule, then show cancellation
53
- handlers.completeActiveAndPending();
54
+ workflowHandlers.completeActiveAndPending();
54
55
  const message = getCancellationMessage(operation);
55
- handlers.addToQueue(createFeedback(FeedbackType.Aborted, message));
56
+ queueHandlers.addToQueue(createFeedback(FeedbackType.Aborted, message));
56
57
  });
57
- handlers.addToQueue(confirmDefinition);
58
+ queueHandlers.addToQueue(confirmDefinition);
58
59
  });
59
- handlers.addToQueue(scheduleDefinition);
60
+ queueHandlers.addToQueue(scheduleDefinition);
60
61
  }
61
62
  }
62
63
  /**
@@ -66,8 +67,8 @@ export function routeTasksWithConfirm(tasks, message, service, userRequest, hand
66
67
  function validateTaskTypes(tasks) {
67
68
  if (tasks.length === 0)
68
69
  return;
69
- // Cast to ScheduledTask to access subtasks property
70
- const scheduledTasks = tasks;
70
+ // Convert to ScheduledTask to access subtasks property
71
+ const scheduledTasks = asScheduledTasks(tasks);
71
72
  // Check each Group task's subtasks for uniform types
72
73
  for (const task of scheduledTasks) {
73
74
  if (task.type === TaskType.Group &&
@@ -87,16 +88,16 @@ function validateTaskTypes(tasks) {
87
88
  * Validates task types and routes each type appropriately
88
89
  * Supports mixed types at top level with Groups
89
90
  */
90
- function executeTasksAfterConfirm(tasks, service, userRequest, handlers) {
91
+ function executeTasksAfterConfirm(tasks, service, userRequest, queueHandlers, errorHandlers) {
91
92
  // Validate task types (Groups must have uniform subtasks)
92
93
  try {
93
94
  validateTaskTypes(tasks);
94
95
  }
95
96
  catch (error) {
96
- handlers.onError(error instanceof Error ? error.message : String(error));
97
+ errorHandlers.onError(error instanceof Error ? error.message : String(error));
97
98
  return;
98
99
  }
99
- const scheduledTasks = tasks;
100
+ const scheduledTasks = asScheduledTasks(tasks);
100
101
  // Process tasks in order, preserving Group boundaries
101
102
  // Track consecutive standalone tasks to group them by type
102
103
  let consecutiveStandaloneTasks = [];
@@ -116,7 +117,7 @@ function executeTasksAfterConfirm(tasks, service, userRequest, handlers) {
116
117
  const taskType = type;
117
118
  if (typeTasks.length === 0)
118
119
  continue;
119
- routeTasksByType(taskType, typeTasks, service, userRequest, handlers);
120
+ routeTasksByType(taskType, typeTasks, service, userRequest, queueHandlers, errorHandlers);
120
121
  }
121
122
  consecutiveStandaloneTasks = [];
122
123
  };
@@ -129,7 +130,7 @@ function executeTasksAfterConfirm(tasks, service, userRequest, handlers) {
129
130
  if (task.subtasks.length > 0) {
130
131
  const subtasks = task.subtasks;
131
132
  const taskType = subtasks[0].type;
132
- routeTasksByType(taskType, subtasks, service, userRequest, handlers);
133
+ routeTasksByType(taskType, subtasks, service, userRequest, queueHandlers, errorHandlers);
133
134
  }
134
135
  }
135
136
  else {
@@ -144,22 +145,22 @@ function executeTasksAfterConfirm(tasks, service, userRequest, handlers) {
144
145
  * Route tasks by type to appropriate components
145
146
  * Extracted to allow reuse for both Groups and standalone tasks
146
147
  */
147
- function routeTasksByType(taskType, typeTasks, service, userRequest, handlers) {
148
+ function routeTasksByType(taskType, typeTasks, service, userRequest, queueHandlers, errorHandlers) {
148
149
  if (taskType === TaskType.Answer) {
149
150
  // Create separate Answer component for each question
150
151
  for (const task of typeTasks) {
151
- handlers.addToQueue(createAnswerDefinition(task.action, service));
152
+ queueHandlers.addToQueue(createAnswerDefinition(task.action, service));
152
153
  }
153
154
  }
154
155
  else if (taskType === TaskType.Introspect) {
155
- handlers.addToQueue(createIntrospectDefinition(typeTasks, service));
156
+ queueHandlers.addToQueue(createIntrospectDefinition(typeTasks, service));
156
157
  }
157
158
  else if (taskType === TaskType.Config) {
158
159
  // Route to Config flow - extract keys from task params
159
160
  const configKeys = typeTasks
160
161
  .map((task) => task.params?.key)
161
162
  .filter((key) => key !== undefined);
162
- handlers.addToQueue(createConfigDefinitionWithKeys(configKeys, (config) => {
163
+ queueHandlers.addToQueue(createConfigDefinitionWithKeys(configKeys, (config) => {
163
164
  // Save config - Config component will handle completion and feedback
164
165
  try {
165
166
  // Convert flat dotted keys to nested structure grouped by section
@@ -176,7 +177,7 @@ function routeTasksByType(taskType, typeTasks, service, userRequest, handlers) {
176
177
  throw new Error(errorMessage);
177
178
  }
178
179
  }, (operation) => {
179
- handlers.onAborted(operation);
180
+ errorHandlers.onAborted(operation);
180
181
  }));
181
182
  }
182
183
  else if (taskType === TaskType.Execute) {
@@ -191,26 +192,26 @@ function routeTasksByType(taskType, typeTasks, service, userRequest, handlers) {
191
192
  .join('\n');
192
193
  return `Invalid skill definition "${error.skill}":\n\n${issuesList}`;
193
194
  });
194
- handlers.addToQueue(createFeedback(FeedbackType.Failed, errorMessages.join('\n\n')));
195
+ queueHandlers.addToQueue(createFeedback(FeedbackType.Failed, errorMessages.join('\n\n')));
195
196
  }
196
197
  else if (validation.missingConfig.length > 0) {
197
- handlers.addToQueue(createValidateDefinition(validation.missingConfig, userRequest, service, (error) => {
198
- handlers.onError(error);
198
+ queueHandlers.addToQueue(createValidateDefinition(validation.missingConfig, userRequest, service, (error) => {
199
+ errorHandlers.onError(error);
199
200
  }, () => {
200
- handlers.addToQueue(createExecuteDefinition(typeTasks, service));
201
+ queueHandlers.addToQueue(createExecuteDefinition(typeTasks, service));
201
202
  }, (operation) => {
202
- handlers.onAborted(operation);
203
+ errorHandlers.onAborted(operation);
203
204
  }));
204
205
  }
205
206
  else {
206
- handlers.addToQueue(createExecuteDefinition(typeTasks, service));
207
+ queueHandlers.addToQueue(createExecuteDefinition(typeTasks, service));
207
208
  }
208
209
  }
209
210
  catch (error) {
210
211
  // Handle skill reference errors (e.g., unknown skills)
211
212
  const errorMessage = error instanceof Error ? error.message : String(error);
212
213
  const message = createMessage(errorMessage);
213
- handlers.addToQueue(message);
214
+ queueHandlers.addToQueue(message);
214
215
  }
215
216
  }
216
217
  }
@@ -1,6 +1,7 @@
1
- import { existsSync, readdirSync, readFileSync } from 'fs';
2
1
  import { homedir } from 'os';
3
2
  import { join } from 'path';
3
+ import { defaultFileSystem } from './filesystem.js';
4
+ import { displayWarning } from './logger.js';
4
5
  import { getUnknownSkillMessage } from './messages.js';
5
6
  import { parseSkillMarkdown, displayNameToKey } from './parser.js';
6
7
  /**
@@ -32,7 +33,7 @@ export function isValidSkillFilename(filename) {
32
33
  return kebabCasePattern.test(name);
33
34
  }
34
35
  /**
35
- * Check if skill key conflicts with built-in skills
36
+ * Check if skill key conflicts with system skills
36
37
  */
37
38
  export function conflictsWithBuiltIn(key) {
38
39
  return BUILT_IN_SKILLS.has(key);
@@ -46,16 +47,16 @@ export function getSkillsDirectory() {
46
47
  /**
47
48
  * Load all skill markdown files from the skills directory
48
49
  * Returns an array of objects with filename (key) and content
49
- * Filters out invalid filenames and conflicts with built-in skills
50
+ * Filters out invalid filenames and conflicts with system skills
50
51
  */
51
- export function loadSkills() {
52
+ export function loadSkills(fs = defaultFileSystem) {
52
53
  const skillsDir = getSkillsDirectory();
53
54
  // Return empty array if directory doesn't exist
54
- if (!existsSync(skillsDir)) {
55
+ if (!fs.exists(skillsDir)) {
55
56
  return [];
56
57
  }
57
58
  try {
58
- const files = readdirSync(skillsDir);
59
+ const files = fs.readDirectory(skillsDir);
59
60
  // Filter and map valid skill files
60
61
  return files
61
62
  .filter((file) => {
@@ -65,7 +66,7 @@ export function loadSkills() {
65
66
  }
66
67
  // Extract key (filename without extension, handles both .md and .MD)
67
68
  const key = file.slice(0, -3);
68
- // Must not conflict with built-in skills
69
+ // Must not conflict with system skills
69
70
  if (conflictsWithBuiltIn(key)) {
70
71
  return false;
71
72
  }
@@ -75,12 +76,12 @@ export function loadSkills() {
75
76
  // Extract key (filename without extension, handles both .md and .MD)
76
77
  const key = file.slice(0, -3);
77
78
  const filePath = join(skillsDir, file);
78
- const content = readFileSync(filePath, 'utf-8');
79
+ const content = fs.readFile(filePath, 'utf-8');
79
80
  return { key, content };
80
81
  });
81
82
  }
82
- catch {
83
- // Return empty array if there's any error reading the directory
83
+ catch (error) {
84
+ displayWarning('Failed to load skills directory', error);
84
85
  return [];
85
86
  }
86
87
  }
@@ -88,16 +89,16 @@ export function loadSkills() {
88
89
  * Load and parse all skill definitions
89
90
  * Returns structured skill definitions (including invalid skills)
90
91
  */
91
- export function loadSkillDefinitions() {
92
- const skills = loadSkills();
92
+ export function loadSkillDefinitions(fs = defaultFileSystem) {
93
+ const skills = loadSkills(fs);
93
94
  return skills.map(({ key, content }) => parseSkillMarkdown(key, content));
94
95
  }
95
96
  /**
96
97
  * Load skills and mark incomplete ones in their markdown
97
98
  * Returns array of skill markdown with status markers
98
99
  */
99
- export function loadSkillsWithValidation() {
100
- const skills = loadSkills();
100
+ export function loadSkillsWithValidation(fs = defaultFileSystem) {
101
+ const skills = loadSkills(fs);
101
102
  return skills.map(({ key, content }) => {
102
103
  const parsed = parseSkillMarkdown(key, content);
103
104
  // If skill is incomplete (either validation failed or needs more documentation), append (INCOMPLETE) to the name
@@ -1,17 +1,18 @@
1
+ import { defaultFileSystem } from './filesystem.js';
1
2
  import { loadUserConfig, hasConfigPath } from './loader.js';
2
3
  import { loadSkillDefinitions, createSkillLookup } from './skills.js';
3
4
  /**
4
5
  * Validate config requirements for execute tasks
5
6
  * Returns validation result with missing config and validation errors
6
7
  */
7
- export function validateExecuteTasks(tasks) {
8
- const userConfig = loadUserConfig();
8
+ export function validateExecuteTasks(tasks, fs = defaultFileSystem) {
9
+ const userConfig = loadUserConfig(fs);
9
10
  const missing = [];
10
11
  const seenPaths = new Set();
11
12
  const validationErrors = [];
12
13
  const seenSkills = new Set();
13
14
  // Load all skills (including invalid ones for validation)
14
- const parsedSkills = loadSkillDefinitions();
15
+ const parsedSkills = loadSkillDefinitions(fs);
15
16
  const skillLookup = createSkillLookup(parsedSkills);
16
17
  // Check for invalid skills being used in tasks
17
18
  for (const task of tasks) {
@@ -26,8 +26,8 @@ You will receive:
26
26
 
27
27
  ## Task
28
28
 
29
- Present the concierge's capabilities as a list of tasks, each representing
30
- one capability.
29
+ Present the concierge's capabilities as a list of capability objects, each
30
+ with a name, description, and origin.
31
31
 
32
32
  ## Response Format
33
33
 
@@ -77,7 +77,7 @@ NON-NEGOTIABLE and applies to EVERY response.
77
77
 
78
78
  **CORRECT ORDER - FOLLOW EXACTLY:**
79
79
 
80
- ### Position 1-4: Built-in Capabilities (Direct User Operations)
80
+ ### Position 1-4: system capabilities (origin: "system")
81
81
 
82
82
  These MUST appear FIRST, in this EXACT sequence:
83
83
 
@@ -86,47 +86,56 @@ These MUST appear FIRST, in this EXACT sequence:
86
86
  3. **Answer** ← ALWAYS THIRD
87
87
  4. **Execute** ← ALWAYS FOURTH
88
88
 
89
- ### Position 5-7: Indirect Workflow Capabilities
89
+ ### Position 5-7: meta workflow capabilities (origin: "meta")
90
90
 
91
- These MUST appear AFTER Execute and BEFORE user skills:
91
+ These MUST appear AFTER Execute and BEFORE user-provided skills:
92
92
 
93
93
  5. **Schedule** ← NEVER FIRST, ALWAYS position 5 (after Execute)
94
94
  6. **Validate** ← ALWAYS position 6 (after Schedule)
95
95
  7. **Report** ← NEVER FIRST, ALWAYS position 7 (after Validate)
96
96
 
97
- ### 3. User-Defined Skills
97
+ ### 3. user-provided skills (origin: "user")
98
98
 
99
99
  If skills are provided in the "Available Skills" section below, include
100
100
  them in the response. For each skill:
101
101
  - Extract the skill name from the first heading (# Skill Name)
102
- - If the skill name contains "(INCOMPLETE)", preserve it exactly in the
103
- task action
102
+ - Set origin to "user"
103
+ - If the skill name contains "(INCOMPLETE)", set isIncomplete to true and
104
+ remove "(INCOMPLETE)" from the name
104
105
  - Extract a brief description from the Description or Overview section
105
106
  - Keep descriptions concise (1-2 lines maximum)
106
107
  - If the user specified a filter (e.g., "skills for deployment"), only
107
108
  include skills whose name or description matches the filter
108
109
 
109
- ## Task Definition Guidelines
110
+ ## Capability Object Guidelines
110
111
 
111
- Create tasks with type "introspect" for each capability. Each task should:
112
+ Create capability objects for each capability. Each object should have:
112
113
 
113
- - **Action**: The capability name and a concise description
114
- - Format: "Capability Name: description" (note: display format will use
115
- " - " separator)
116
- - **IMPORTANT**: Use title case for capability names (e.g., "Schedule",
117
- "Execute"), NOT all uppercase (NOT "SCHEDULE", "EXECUTE")
114
+ - **name**: The capability or skill name
115
+ - Use title case (e.g., "Schedule", "Execute", "Deploy Application")
116
+ - NOT all uppercase (NOT "SCHEDULE", "EXECUTE")
117
+ - Maximum 32 characters
118
+ - Examples: "Introspect", "Execute", "Deploy Application"
119
+
120
+ - **description**: A concise description of what this capability does
121
+ - Maximum 64 characters
122
+ - Start with lowercase letter, no ending punctuation
123
+ - Focus on clarity and brevity
124
+ - Describe the core purpose in one short phrase
118
125
  - Examples:
119
- - "Schedule: break down requests into actionable steps"
120
- - "Execute: run shell commands and process operations"
121
- - "Deploy Application: build and deploy to staging or production"
122
- - **Type**: Always use "introspect"
123
- - **Params**: Omit params field
124
-
125
- **Keep action descriptions concise:**
126
- - Maximum 60 characters for the description portion (after the colon)
127
- - Focus on clarity and brevity
128
- - Describe the core purpose in one short phrase
129
- - Start descriptions with a lowercase letter (they follow a colon)
126
+ - "break down requests into actionable steps"
127
+ - "run shell commands and process operations"
128
+ - "build and deploy to staging or production"
129
+
130
+ - **origin**: The origin type of the capability
131
+ - Use "system" for system capabilities: Introspect, Configure, Answer,
132
+ Execute
133
+ - Use "meta" for meta workflow capabilities: Schedule, Validate, Report
134
+ - Use "user" for all user-provided skills
135
+
136
+ - **isIncomplete**: Optional boolean flag
137
+ - Only include if the skill is marked as incomplete
138
+ - Set to true if skill name contained "(INCOMPLETE)"
130
139
 
131
140
  ## Filtering
132
141
 
@@ -134,48 +143,48 @@ When the user specifies a filter (e.g., "skills for deployment", "what
134
143
  can you do with files"):
135
144
  1. Parse the filter keyword(s) from the request
136
145
  2. Match against skill names and descriptions (case-insensitive)
137
- 3. Include built-in capabilities if they match the filter
146
+ 3. Include system capabilities if they match the filter
138
147
  4. Only present capabilities that match the filter
139
148
 
140
149
  Examples:
141
150
  - "skills for deployment" → Only show skills with "deploy" in
142
151
  name/description
143
152
  - "what can you do with files" → Show EXECUTE and any file-related skills
144
- - "list all skills" → Show all built-in capabilities + all user skills
153
+ - "list all skills" → Show all system capabilities + all user-provided skills
145
154
 
146
155
  ## Examples
147
156
 
148
157
  ### Example 1: List All Capabilities
149
158
 
150
159
  When user asks "list your skills", create an introductory message like
151
- "here are my capabilities:" followed by tasks for built-in capabilities
152
- (Introspect, Configure, Answer, Execute), then indirect workflow capabilities
153
- (Schedule, Validate, Report).
154
-
155
- Each task uses type "introspect" with an action describing the
156
- capability.
160
+ "here are my capabilities:" followed by capability objects for system
161
+ capabilities (Introspect, Configure, Answer, Execute with origin
162
+ "system"), then meta workflow capabilities (Schedule, Validate, Report
163
+ with origin "meta").
157
164
 
158
165
  ### Example 2: Filtered Skills
159
166
 
160
167
  When user asks "skills for deployment" and a "deploy app" skill exists,
161
168
  create an introductory message like "these skills match 'deployment':"
162
- followed by only the tasks that match the filter. In this case, show the
163
- deploy app skill with its description.
169
+ followed by only the capabilities that match the filter. Show the deploy
170
+ app skill with origin "user".
164
171
 
165
172
  ### Example 3: With User Skills
166
173
 
167
- When user asks "what can you do" and user-defined skills like "process
174
+ When user asks "what can you do" and user-provided skills like "process
168
175
  data" and "backup files" exist, create an introductory message like "i can
169
- help with these operations:" followed by all built-in capabilities
170
- (Introspect, Configure, Answer, Execute, Validate, Schedule, Report) plus the
171
- user-defined skills. Each capability and skill becomes a task with type
172
- "introspect".
176
+ help with these operations:" followed by all system capabilities
177
+ (Introspect, Configure, Answer, Execute with origin "system"), meta
178
+ capabilities (Schedule, Validate, Report with origin "meta"), plus the
179
+ user-provided skills with origin "user".
173
180
 
174
181
  ## Final Validation
175
182
 
176
183
  Before finalizing:
177
- 1. Ensure every task has type "introspect"
178
- 2. Verify action descriptions are concise (≤64 characters)
184
+ 1. Ensure every capability has the correct origin value ("system",
185
+ "meta", or "user")
186
+ 2. Verify descriptions are concise (≤64 characters)
179
187
  3. Confirm the introductory message ends with a colon
180
188
  4. Check that filtering was applied correctly if specified
181
189
  5. Ensure no duplicate capabilities are listed
190
+ 6. Verify names use title case, not all uppercase
@@ -83,12 +83,17 @@ settings", type "configure", params { query: "app" }
83
83
 
84
84
  Before creating tasks, evaluate the request type:
85
85
 
86
- 1. **Information requests** (questions) - Use question keywords:
86
+ 1. **Introspection requests** - User asks about your capabilities:
87
+ - "list your skills", "what can you do", "flex", "show off", "list
88
+ capabilities", "show skills"
89
+ - Example: "flex" → introspect type
90
+
91
+ 2. **Information requests** (questions) - Use question keywords:
87
92
  - "explain", "describe", "tell me", "what is", "how does", "find",
88
93
  "search"
89
94
  - Example: "explain docker" → answer type
90
95
 
91
- 2. **Action requests** (commands) - Must match available skills:
96
+ 3. **Action requests** (commands) - Must match available skills:
92
97
  - Action verbs like "compile", "deploy", "process", "validate"
93
98
  - If verb matches a skill → extract skill steps as subtasks
94
99
  - If verb does NOT match any skill → ignore type with action
@@ -98,7 +103,7 @@ Before creating tasks, evaluate the request type:
98
103
  - Example: "validate" with no skill → action "Ignore unknown
99
104
  'validate' request"
100
105
 
101
- 3. **Vague/ambiguous requests** without clear verb:
106
+ 4. **Vague/ambiguous requests** without clear verb:
102
107
  - Phrases like "do something", "handle it" → ignore type
103
108
  - Action format: "Ignore unknown 'X' request" where X is the phrase
104
109
 
@@ -1,6 +1,6 @@
1
1
  export const introspectTool = {
2
2
  name: 'introspect',
3
- description: 'Execute a task with type "introspect" to list available capabilities and skills. Called after SCHEDULE has identified an introspection request and user has confirmed. Takes the task action and optional filter parameter to present built-in capabilities and user-defined skills.',
3
+ description: 'Execute a task with type "introspect" to list available capabilities and skills. Called after SCHEDULE has identified an introspection request and user has confirmed. Takes the task action and optional filter parameter to present system capabilities and user-provided skills.',
4
4
  input_schema: {
5
5
  type: 'object',
6
6
  properties: {
@@ -8,25 +8,34 @@ export const introspectTool = {
8
8
  type: 'string',
9
9
  description: 'Introductory reply to display before the capabilities list. Must be a single sentence, maximum 64 characters (including the colon at the end). Vary this naturally - try to use a different phrase each time. Always end with a colon.',
10
10
  },
11
- tasks: {
11
+ capabilities: {
12
12
  type: 'array',
13
- description: 'Array of capabilities, each with type "introspect". Include built-in capabilities (SCHEDULE, INTROSPECT, ANSWER, EXECUTE, REPORT, CONFIGURE) and user-defined skills from the Available Skills section.',
13
+ description: 'Array of capabilities and skills. Include system capabilities (Introspect, Configure, Answer, Execute) with origin "system", meta workflow capabilities (Schedule, Validate, Report) with origin "meta", and user-provided skills from the Available Skills section with origin "user".',
14
14
  items: {
15
15
  type: 'object',
16
16
  properties: {
17
- action: {
17
+ name: {
18
18
  type: 'string',
19
- description: 'Capability name and description. Format: "NAME: Brief description". Maximum 64 characters. Examples: "SCHEDULE: Break down requests into steps", "Deploy App: Build and deploy application".',
19
+ description: 'Capability or skill name. Use title case. Maximum 32 characters. Examples: "Execute", "Deploy Application", "Process Data".',
20
20
  },
21
- type: {
21
+ description: {
22
22
  type: 'string',
23
- description: 'Always "introspect" for capability listings.',
23
+ description: 'Brief description of what this capability does. Start with lowercase letter, no ending punctuation. Maximum 64 characters. Examples: "run shell commands and operations", "build and deploy to production".',
24
+ },
25
+ origin: {
26
+ type: 'string',
27
+ enum: ['system', 'user', 'meta'],
28
+ description: 'Origin of the capability. Use "system" for system capabilities (Introspect, Configure, Answer, Execute), "meta" for meta workflow capabilities (Schedule, Validate, Report), and "user" for user-provided skills.',
29
+ },
30
+ isIncomplete: {
31
+ type: 'boolean',
32
+ description: 'Optional. Set to true if the skill is marked as incomplete.',
24
33
  },
25
34
  },
26
- required: ['action', 'type'],
35
+ required: ['name', 'description', 'origin'],
27
36
  },
28
37
  },
29
38
  },
30
- required: ['message', 'tasks'],
39
+ required: ['message', 'capabilities'],
31
40
  },
32
41
  };