prompt-language-shell 0.7.8 → 0.8.2

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.
@@ -48,8 +48,8 @@ export function cleanAnswerText(text) {
48
48
  export class AnthropicService {
49
49
  client;
50
50
  model;
51
- constructor(key, model = 'claude-haiku-4-5-20251001') {
52
- this.client = new Anthropic({ apiKey: key });
51
+ constructor(key, model = 'claude-haiku-4-5', timeout = 30000) {
52
+ this.client = new Anthropic({ apiKey: key, timeout });
53
53
  this.model = model;
54
54
  }
55
55
  async processWithTool(command, toolName, customInstructions) {
@@ -186,7 +186,33 @@ export class AnthropicService {
186
186
  debug,
187
187
  };
188
188
  }
189
- // Handle schedule and introspect tool responses
189
+ // Handle introspect tool response
190
+ if (toolName === 'introspect') {
191
+ if (!input.message || typeof input.message !== 'string') {
192
+ throw new Error('Invalid tool response: missing or invalid message field');
193
+ }
194
+ if (!input.capabilities || !Array.isArray(input.capabilities)) {
195
+ throw new Error('Invalid tool response: missing or invalid capabilities array');
196
+ }
197
+ // Validate each capability has required fields
198
+ input.capabilities.forEach((cap, i) => {
199
+ if (!cap.name || typeof cap.name !== 'string') {
200
+ throw new Error(`Invalid capability at index ${String(i)}: missing or invalid 'name' field`);
201
+ }
202
+ if (!cap.description || typeof cap.description !== 'string') {
203
+ throw new Error(`Invalid capability at index ${String(i)}: missing or invalid 'description' field`);
204
+ }
205
+ if (typeof cap.origin !== 'string') {
206
+ throw new Error(`Invalid capability at index ${String(i)}: invalid 'origin' field`);
207
+ }
208
+ });
209
+ return {
210
+ message: input.message,
211
+ capabilities: input.capabilities,
212
+ debug,
213
+ };
214
+ }
215
+ // Handle schedule tool responses
190
216
  if (input.message === undefined || typeof input.message !== 'string') {
191
217
  throw new Error('Invalid tool response: missing or invalid message field');
192
218
  }
@@ -1,4 +1,4 @@
1
- import { FeedbackType, TaskType } from '../types/types.js';
1
+ import { FeedbackType, Origin, TaskType } from '../types/types.js';
2
2
  import { DebugLevel } from './configuration.js';
3
3
  import { ExecutionStatus } from './shell.js';
4
4
  /**
@@ -8,7 +8,6 @@ import { ExecutionStatus } from './shell.js';
8
8
  export const Palette = {
9
9
  White: '#ffffff',
10
10
  AshGray: '#d0d0d0',
11
- PaleGreen: '#a8dcbc',
12
11
  Gray: '#888888',
13
12
  DarkGray: '#666666',
14
13
  CharcoalGray: '#282828',
@@ -16,8 +15,8 @@ export const Palette = {
16
15
  LightGreen: '#65b595',
17
16
  BrightGreen: '#3e9a3e',
18
17
  Yellow: '#cccc5c',
19
- LightYellow: '#d4d47a',
20
18
  Orange: '#f48c80',
19
+ MediumOrange: '#d07560',
21
20
  DarkOrange: '#ab5e40',
22
21
  BurntOrange: '#cc7a5c',
23
22
  Red: '#cc5c5c',
@@ -47,7 +46,7 @@ export const Colors = {
47
46
  Status: {
48
47
  Success: Palette.BrightGreen,
49
48
  Error: Palette.Red,
50
- Warning: Palette.Orange,
49
+ Warning: Palette.MediumOrange,
51
50
  Info: Palette.Cyan,
52
51
  },
53
52
  Label: {
@@ -130,9 +129,17 @@ const taskColors = {
130
129
  const feedbackColors = {
131
130
  [FeedbackType.Info]: Colors.Status.Info,
132
131
  [FeedbackType.Succeeded]: Colors.Status.Success,
133
- [FeedbackType.Aborted]: Colors.Status.Warning,
132
+ [FeedbackType.Aborted]: Palette.MediumOrange,
134
133
  [FeedbackType.Failed]: Colors.Status.Error,
135
134
  };
135
+ /**
136
+ * Origin-specific color mappings (internal)
137
+ */
138
+ const originColors = {
139
+ [Origin.BuiltIn]: Colors.Origin.BuiltIn,
140
+ [Origin.UserProvided]: Colors.Origin.UserProvided,
141
+ [Origin.Indirect]: Colors.Origin.Indirect,
142
+ };
136
143
  /**
137
144
  * Process null color values based on current/historical state.
138
145
  *
@@ -171,6 +178,17 @@ export function getTaskColors(type, isCurrent) {
171
178
  export function getFeedbackColor(type, isCurrent) {
172
179
  return processColor(feedbackColors[type], isCurrent);
173
180
  }
181
+ /**
182
+ * Get color for capability origin.
183
+ *
184
+ * Returns the color associated with each origin type:
185
+ * - BuiltIn: Cyan
186
+ * - UserProvided: Green
187
+ * - Indirect: Purple
188
+ */
189
+ export function getOriginColor(origin) {
190
+ return originColors[origin];
191
+ }
174
192
  /**
175
193
  * Get text color based on current/historical state.
176
194
  *
@@ -220,6 +238,7 @@ export const STATUS_ICONS = {
220
238
  [ExecutionStatus.Success]: '✓ ',
221
239
  [ExecutionStatus.Failed]: '✗ ',
222
240
  [ExecutionStatus.Aborted]: '⊘ ',
241
+ [ExecutionStatus.Cancelled]: '⊘ ',
223
242
  };
224
243
  /**
225
244
  * Get colors for different execution status states.
@@ -249,7 +268,7 @@ export function getStatusColors(status) {
249
268
  case ExecutionStatus.Success:
250
269
  return {
251
270
  icon: Colors.Status.Success,
252
- description: getTextColor(true),
271
+ description: Palette.AshGray,
253
272
  command: Palette.Gray,
254
273
  symbol: Palette.Gray,
255
274
  };
@@ -262,10 +281,17 @@ export function getStatusColors(status) {
262
281
  };
263
282
  case ExecutionStatus.Aborted:
264
283
  return {
265
- icon: Palette.DarkOrange,
266
- description: getTextColor(true),
267
- command: Palette.DarkOrange,
284
+ icon: Palette.MediumOrange,
285
+ description: Palette.Gray,
286
+ command: Palette.MediumOrange,
268
287
  symbol: Palette.Gray,
269
288
  };
289
+ case ExecutionStatus.Cancelled:
290
+ return {
291
+ icon: Palette.DarkGray,
292
+ description: Palette.DarkGray,
293
+ command: Palette.DarkGray,
294
+ symbol: Palette.DarkGray,
295
+ };
270
296
  }
271
297
  }
@@ -1,8 +1,8 @@
1
1
  import { randomUUID } from 'node:crypto';
2
2
  import { existsSync, readFileSync } from 'node:fs';
3
- import { ComponentName } from '../types/types.js';
4
- import { ComponentStatus, } from '../types/components.js';
5
3
  import { parse as parseYaml } from 'yaml';
4
+ import { ComponentStatus, } from '../types/components.js';
5
+ import { ComponentName } from '../types/types.js';
6
6
  import { ConfigDefinitionType, getConfigPath, getConfigSchema, loadConfig, } from './configuration.js';
7
7
  import { getConfirmationMessage } from './messages.js';
8
8
  import { StepType } from '../ui/Config.js';
@@ -78,7 +78,7 @@ export function createConfigStepsFromSchema(keys) {
78
78
  // Config file doesn't exist or can't be parsed
79
79
  }
80
80
  return keys.map((key) => {
81
- // Check if key is in schema (built-in config)
81
+ // Check if key is in schema (system config)
82
82
  if (!(key in schema)) {
83
83
  // Key is not in schema - it's from a skill or discovered config
84
84
  // Create a simple text step with the full path as description
@@ -180,7 +180,11 @@ export function createConfigDefinition(onFinished, onAborted) {
180
180
  id: randomUUID(),
181
181
  name: ComponentName.Config,
182
182
  status: ComponentStatus.Awaiting,
183
- state: {},
183
+ state: {
184
+ values: {},
185
+ completedStep: 0,
186
+ selectedIndex: 0,
187
+ },
184
188
  props: {
185
189
  steps: createConfigSteps(),
186
190
  onFinished,
@@ -196,7 +200,11 @@ export function createConfigDefinitionWithKeys(keys, onFinished, onAborted) {
196
200
  id: randomUUID(),
197
201
  name: ComponentName.Config,
198
202
  status: ComponentStatus.Awaiting,
199
- state: {},
203
+ state: {
204
+ values: {},
205
+ completedStep: 0,
206
+ selectedIndex: 0,
207
+ },
200
208
  props: {
201
209
  steps: createConfigStepsFromSchema(keys),
202
210
  onFinished,
@@ -338,7 +346,15 @@ export function createExecuteDefinition(tasks, service) {
338
346
  id: randomUUID(),
339
347
  name: ComponentName.Execute,
340
348
  status: ComponentStatus.Awaiting,
341
- state: {},
349
+ state: {
350
+ error: null,
351
+ message: '',
352
+ summary: '',
353
+ taskInfos: [],
354
+ completed: 0,
355
+ taskExecutionTimes: [],
356
+ completionMessage: null,
357
+ },
342
358
  props: {
343
359
  tasks,
344
360
  service,
@@ -350,7 +366,12 @@ export function createValidateDefinition(missingConfig, userRequest, service, on
350
366
  id: randomUUID(),
351
367
  name: ComponentName.Validate,
352
368
  status: ComponentStatus.Awaiting,
353
- state: {},
369
+ state: {
370
+ error: null,
371
+ completionMessage: null,
372
+ configRequirements: null,
373
+ validated: false,
374
+ },
354
375
  props: {
355
376
  missingConfig,
356
377
  userRequest,
@@ -0,0 +1,75 @@
1
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
2
+ import { homedir } from 'os';
3
+ import { join } from 'path';
4
+ /**
5
+ * Get the path to the config labels cache file
6
+ */
7
+ export function getConfigLabelsCachePath() {
8
+ return join(homedir(), '.pls', 'cache', 'config.json');
9
+ }
10
+ /**
11
+ * Get the cache directory path
12
+ */
13
+ function getCacheDirectoryPath() {
14
+ return join(homedir(), '.pls', 'cache');
15
+ }
16
+ /**
17
+ * Ensure the cache directory exists
18
+ */
19
+ function ensureCacheDirectoryExists() {
20
+ const cacheDir = getCacheDirectoryPath();
21
+ if (!existsSync(cacheDir)) {
22
+ mkdirSync(cacheDir, { recursive: true });
23
+ }
24
+ }
25
+ /**
26
+ * Load config labels from cache file
27
+ * Returns empty object if file doesn't exist or is corrupted
28
+ */
29
+ export function loadConfigLabels() {
30
+ try {
31
+ const cachePath = getConfigLabelsCachePath();
32
+ if (!existsSync(cachePath)) {
33
+ return {};
34
+ }
35
+ const content = readFileSync(cachePath, 'utf-8');
36
+ const parsed = JSON.parse(content);
37
+ // Validate that parsed content is an object
38
+ if (typeof parsed !== 'object' ||
39
+ parsed === null ||
40
+ Array.isArray(parsed)) {
41
+ return {};
42
+ }
43
+ return parsed;
44
+ }
45
+ catch {
46
+ // Return empty object on any error (parse error, read error, etc.)
47
+ return {};
48
+ }
49
+ }
50
+ /**
51
+ * Save multiple config labels to cache
52
+ */
53
+ export function saveConfigLabels(labels) {
54
+ ensureCacheDirectoryExists();
55
+ // Load existing labels and merge with new ones
56
+ const existing = loadConfigLabels();
57
+ const merged = { ...existing, ...labels };
58
+ const cachePath = getConfigLabelsCachePath();
59
+ const content = JSON.stringify(merged, null, 2);
60
+ writeFileSync(cachePath, content, 'utf-8');
61
+ }
62
+ /**
63
+ * Save a single config label to cache
64
+ */
65
+ export function saveConfigLabel(key, label) {
66
+ saveConfigLabels({ [key]: label });
67
+ }
68
+ /**
69
+ * Get a config label from cache
70
+ * Returns undefined if label doesn't exist
71
+ */
72
+ export function getConfigLabel(key) {
73
+ const labels = loadConfigLabels();
74
+ return labels[key];
75
+ }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Utility functions for config manipulation
3
+ */
4
+ /**
5
+ * Flatten nested config object to dot notation
6
+ * Example: { a: { b: 1 } } => { 'a.b': 1 }
7
+ */
8
+ export function flattenConfig(obj, prefix = '') {
9
+ const result = {};
10
+ for (const [key, value] of Object.entries(obj)) {
11
+ const fullKey = prefix ? `${prefix}.${key}` : key;
12
+ if (value && typeof value === 'object' && !Array.isArray(value)) {
13
+ Object.assign(result, flattenConfig(value, fullKey));
14
+ }
15
+ else {
16
+ result[fullKey] = value;
17
+ }
18
+ }
19
+ return result;
20
+ }
@@ -2,6 +2,18 @@ import { existsSync, readFileSync, writeFileSync } from 'fs';
2
2
  import { homedir } from 'os';
3
3
  import { join } from 'path';
4
4
  import YAML from 'yaml';
5
+ import { getConfigLabel } from './config-labels.js';
6
+ import { flattenConfig } from './config-utils.js';
7
+ /**
8
+ * Convert a dotted config key to a readable label
9
+ * Example: "project.alpha.repo" -> "Project Alpha Repo"
10
+ */
11
+ function keyToLabel(key) {
12
+ return key
13
+ .split('.')
14
+ .map((part) => part.charAt(0).toUpperCase() + part.slice(1))
15
+ .join(' ');
16
+ }
5
17
  export var AnthropicModel;
6
18
  (function (AnthropicModel) {
7
19
  AnthropicModel["Sonnet"] = "claude-sonnet-4-5";
@@ -192,7 +204,7 @@ export function getConfigurationRequiredMessage(forFutureUse = false) {
192
204
  return messages[Math.floor(Math.random() * messages.length)];
193
205
  }
194
206
  /**
195
- * Core configuration schema - defines structure and types for built-in settings
207
+ * Core configuration schema - defines structure and types for system settings
196
208
  */
197
209
  const coreConfigSchema = {
198
210
  'anthropic.key': {
@@ -301,19 +313,6 @@ export function getConfiguredKeys() {
301
313
  const content = readFileSync(configFile, 'utf-8');
302
314
  const parsed = YAML.parse(content);
303
315
  // Flatten nested config to dot notation
304
- function flattenConfig(obj, prefix = '') {
305
- const result = {};
306
- for (const [key, value] of Object.entries(obj)) {
307
- const fullKey = prefix ? `${prefix}.${key}` : key;
308
- if (value && typeof value === 'object' && !Array.isArray(value)) {
309
- Object.assign(result, flattenConfig(value, fullKey));
310
- }
311
- else {
312
- result[fullKey] = value;
313
- }
314
- }
315
- return result;
316
- }
317
316
  const flatConfig = flattenConfig(parsed);
318
317
  return Object.keys(flatConfig);
319
318
  }
@@ -337,19 +336,6 @@ export function getAvailableConfigStructure() {
337
336
  const content = readFileSync(configFile, 'utf-8');
338
337
  const parsed = YAML.parse(content);
339
338
  // Flatten nested config to dot notation
340
- function flattenConfig(obj, prefix = '') {
341
- const result = {};
342
- for (const [key, value] of Object.entries(obj)) {
343
- const fullKey = prefix ? `${prefix}.${key}` : key;
344
- if (value && typeof value === 'object' && !Array.isArray(value)) {
345
- Object.assign(result, flattenConfig(value, fullKey));
346
- }
347
- else {
348
- result[fullKey] = value;
349
- }
350
- }
351
- return result;
352
- }
353
339
  flatConfig = flattenConfig(parsed);
354
340
  }
355
341
  }
@@ -357,20 +343,13 @@ export function getAvailableConfigStructure() {
357
343
  // Config file doesn't exist or can't be read
358
344
  }
359
345
  // Add schema keys with descriptions
360
- // Mark optional keys as (optional)
361
346
  for (const [key, definition] of Object.entries(schema)) {
362
- const isOptional = !definition.required;
363
- if (isOptional) {
364
- structure[key] = `${definition.description} (optional)`;
365
- }
366
- else {
367
- structure[key] = definition.description;
368
- }
347
+ structure[key] = definition.description;
369
348
  }
370
349
  // Add discovered keys that aren't in schema
371
350
  for (const key of Object.keys(flatConfig)) {
372
351
  if (!(key in structure)) {
373
- structure[key] = `${key} (discovered)`;
352
+ structure[key] = getConfigLabel(key) || keyToLabel(key);
374
353
  }
375
354
  }
376
355
  return structure;
@@ -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,9 +1,9 @@
1
- import { TaskType } from '../types/types.js';
1
+ import { asScheduledTasks } from '../types/guards.js';
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';
4
- import { FeedbackType } from '../types/types.js';
5
- import { validateExecuteTasks } from './validator.js';
6
5
  import { getCancellationMessage, getMixedTaskTypesError, getUnknownRequestMessage, } from './messages.js';
6
+ import { validateExecuteTasks } from './validator.js';
7
7
  /**
8
8
  * Determine the operation name based on task types
9
9
  */
@@ -67,8 +67,8 @@ export function routeTasksWithConfirm(tasks, message, service, userRequest, hand
67
67
  function validateTaskTypes(tasks) {
68
68
  if (tasks.length === 0)
69
69
  return;
70
- // Cast to ScheduledTask to access subtasks property
71
- const scheduledTasks = tasks;
70
+ // Convert to ScheduledTask to access subtasks property
71
+ const scheduledTasks = asScheduledTasks(tasks);
72
72
  // Check each Group task's subtasks for uniform types
73
73
  for (const task of scheduledTasks) {
74
74
  if (task.type === TaskType.Group &&
@@ -97,7 +97,7 @@ function executeTasksAfterConfirm(tasks, service, userRequest, handlers) {
97
97
  handlers.onError(error instanceof Error ? error.message : String(error));
98
98
  return;
99
99
  }
100
- const scheduledTasks = tasks;
100
+ const scheduledTasks = asScheduledTasks(tasks);
101
101
  // Process tasks in order, preserving Group boundaries
102
102
  // Track consecutive standalone tasks to group them by type
103
103
  let consecutiveStandaloneTasks = [];
@@ -5,6 +5,7 @@ export var ExecutionStatus;
5
5
  ExecutionStatus["Success"] = "success";
6
6
  ExecutionStatus["Failed"] = "failed";
7
7
  ExecutionStatus["Aborted"] = "aborted";
8
+ ExecutionStatus["Cancelled"] = "cancelled";
8
9
  })(ExecutionStatus || (ExecutionStatus = {}));
9
10
  export var ExecutionResult;
10
11
  (function (ExecutionResult) {
@@ -32,7 +32,7 @@ export function isValidSkillFilename(filename) {
32
32
  return kebabCasePattern.test(name);
33
33
  }
34
34
  /**
35
- * Check if skill key conflicts with built-in skills
35
+ * Check if skill key conflicts with system skills
36
36
  */
37
37
  export function conflictsWithBuiltIn(key) {
38
38
  return BUILT_IN_SKILLS.has(key);
@@ -46,7 +46,7 @@ export function getSkillsDirectory() {
46
46
  /**
47
47
  * Load all skill markdown files from the skills directory
48
48
  * Returns an array of objects with filename (key) and content
49
- * Filters out invalid filenames and conflicts with built-in skills
49
+ * Filters out invalid filenames and conflicts with system skills
50
50
  */
51
51
  export function loadSkills() {
52
52
  const skillsDir = getSkillsDirectory();
@@ -65,7 +65,7 @@ export function loadSkills() {
65
65
  }
66
66
  // Extract key (filename without extension, handles both .md and .MD)
67
67
  const key = file.slice(0, -3);
68
- // Must not conflict with built-in skills
68
+ // Must not conflict with system skills
69
69
  if (conflictsWithBuiltIn(key)) {
70
70
  return false;
71
71
  }
@@ -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