prompt-language-shell 0.7.2 → 0.7.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -159,7 +159,6 @@ $ pls build test
159
159
 
160
160
  ## Roadmap
161
161
 
162
- - **0.7** - Comprehend skill, simplified prompts, better debugging
163
162
  - **0.8** - Sequential and interlaced skill execution
164
163
  - **0.9** - Learn skill, codebase refinement, complex dependency handling
165
164
  - **1.0** - Production release
@@ -52,31 +52,39 @@ export class AnthropicService {
52
52
  this.client = new Anthropic({ apiKey: key });
53
53
  this.model = model;
54
54
  }
55
- async processWithTool(command, toolName) {
55
+ async processWithTool(command, toolName, customInstructions) {
56
56
  // Load tool from registry
57
57
  const tool = toolRegistry.getSchema(toolName);
58
- const instructions = toolRegistry.getInstructions(toolName);
59
- // Build system prompt with additional context based on tool
60
- let systemPrompt = instructions;
61
- // Add skills section for applicable tools
62
- if (toolName === 'plan' ||
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
- // Add config structure for config tool only
71
- if (toolName === 'configure') {
72
- const configStructure = getAvailableConfigStructure();
73
- const configuredKeys = getConfiguredKeys();
74
- const configSection = '\n## Available Configuration\n\n' +
75
- 'Config structure (key: description):\n' +
76
- JSON.stringify(configStructure, null, 2) +
77
- '\n\nConfigured keys (keys that exist in config file):\n' +
78
- JSON.stringify(configuredKeys, null, 2);
79
- systemPrompt += configSection;
64
+ else {
65
+ // Load and build system prompt automatically (production)
66
+ const instructions = toolRegistry.getInstructions(toolName);
67
+ systemPrompt = instructions;
68
+ // Add skills section for applicable tools
69
+ if (toolName === 'schedule' ||
70
+ toolName === 'introspect' ||
71
+ toolName === 'execute' ||
72
+ toolName === 'validate') {
73
+ const skills = loadSkillsWithValidation();
74
+ const skillsSection = formatSkillsForPrompt(skills);
75
+ systemPrompt += skillsSection;
76
+ }
77
+ // Add config structure for config tool only
78
+ if (toolName === 'config') {
79
+ const configStructure = getAvailableConfigStructure();
80
+ const configuredKeys = getConfiguredKeys();
81
+ const configSection = '\n## Available Configuration\n\n' +
82
+ 'Config structure (key: description):\n' +
83
+ JSON.stringify(configStructure, null, 2) +
84
+ '\n\nConfigured keys (keys that exist in config file):\n' +
85
+ JSON.stringify(configuredKeys, null, 2);
86
+ systemPrompt += configSection;
87
+ }
80
88
  }
81
89
  // Build tools array - add web search for answer tool
82
90
  const tools = [tool];
@@ -177,7 +185,7 @@ export class AnthropicService {
177
185
  debug,
178
186
  };
179
187
  }
180
- // Handle plan and introspect tool responses
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
  }
@@ -57,7 +57,7 @@ export const Colors = {
57
57
  },
58
58
  Type: {
59
59
  Config: Palette.Cyan,
60
- Plan: Palette.LightCyan,
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.Plan]: {
85
+ [TaskType.Schedule]: {
85
86
  description: Colors.Label.Default,
86
- type: Colors.Type.Plan,
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.Plan]: 'plan tasks',
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 createPlanDefinition(message, tasks, onSelectionConfirmed) {
219
+ export function createScheduleDefinition(message, tasks, onSelectionConfirmed) {
220
220
  return {
221
221
  id: randomUUID(),
222
- name: ComponentName.Plan,
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, 'plan');
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 { planTool } from '../tools/plan.tool.js';
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
- plan: planTool,
47
+ schedule: scheduleTool,
48
48
  validate: validateTool,
49
49
  };
50
50
  for (const [name, schema] of Object.entries(tools)) {
@@ -1,5 +1,5 @@
1
1
  import { TaskType } from '../types/types.js';
2
- import { createAnswerDefinition, createConfigDefinitionWithKeys, createConfirmDefinition, createExecuteDefinition, createFeedback, createIntrospectDefinition, createMessage, createPlanDefinition, createValidateDefinition, } from './components.js';
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 Plan to queue for user selection
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 planDefinition = createPlanDefinition(message, validTasks);
39
- handlers.addToQueue(planDefinition);
38
+ const scheduleDefinition = createScheduleDefinition(message, validTasks);
39
+ handlers.addToQueue(scheduleDefinition);
40
40
  }
41
41
  else {
42
- // No DEFINE tasks - Plan auto-completes and adds Confirm to queue
43
- // When Plan activates, Command moves to timeline
44
- // When Plan completes, it moves to pending
45
- // When Confirm activates, Plan stays pending (visible for context)
46
- const planDefinition = createPlanDefinition(message, validTasks, () => {
47
- // Plan completed - add Confirm to queue
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 Plan, then route to appropriate component
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 Plan, then show cancellation
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(planDefinition);
60
+ handlers.addToQueue(scheduleDefinition);
61
61
  }
62
62
  }
63
63
  /**
64
- * Validate that all tasks have the same type
65
- * Per FLOWS.md: "Mixed types Error (not supported)"
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
- const types = new Set(tasks.map((task) => task.type));
71
- if (types.size > 1) {
72
- throw new Error(getMixedTaskTypesError(Array.from(types)));
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 after user has seen and confirmed the plan
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 all tasks have the same type after user confirmation
81
- // Per FLOWS.md: "Confirm component completes → Execution handler analyzes task types"
92
+ // Validate task types (Groups must have uniform subtasks)
82
93
  try {
83
94
  validateTaskTypes(tasks);
84
95
  }
@@ -86,73 +97,99 @@ function executeTasksAfterConfirm(tasks, service, userRequest, handlers) {
86
97
  handlers.onError(error instanceof Error ? error.message : String(error));
87
98
  return;
88
99
  }
89
- const allIntrospect = tasks.every((task) => task.type === TaskType.Introspect);
90
- const allAnswer = tasks.every((task) => task.type === TaskType.Answer);
91
- const allConfig = tasks.every((task) => task.type === TaskType.Config);
92
- if (allAnswer) {
93
- const question = tasks[0].action;
94
- handlers.addToQueue(createAnswerDefinition(question, service));
100
+ // Flatten Group tasks to get actual executable subtasks
101
+ const flattenedTasks = [];
102
+ const scheduledTasks = tasks;
103
+ for (const task of scheduledTasks) {
104
+ if (task.type === TaskType.Group && task.subtasks) {
105
+ // Add all subtasks from the group
106
+ flattenedTasks.push(...task.subtasks);
107
+ }
108
+ else {
109
+ // Add non-group tasks as-is
110
+ flattenedTasks.push(task);
111
+ }
95
112
  }
96
- else if (allIntrospect) {
97
- handlers.addToQueue(createIntrospectDefinition(tasks, service));
113
+ // Group flattened tasks by type - initialize all TaskType keys with empty arrays
114
+ const tasksByType = {};
115
+ for (const type of Object.values(TaskType)) {
116
+ tasksByType[type] = [];
98
117
  }
99
- else if (allConfig) {
100
- // Route to Config flow - extract keys from task params
101
- const configKeys = tasks
102
- .map((task) => task.params?.key)
103
- .filter((key) => key !== undefined);
104
- handlers.addToQueue(createConfigDefinitionWithKeys(configKeys, (config) => {
105
- // Save config - Config component will handle completion and feedback
118
+ for (const task of flattenedTasks) {
119
+ tasksByType[task.type].push(task);
120
+ }
121
+ // Route each type group appropriately
122
+ for (const [type, typeTasks] of Object.entries(tasksByType)) {
123
+ const taskType = type;
124
+ // Skip empty task groups (pre-initialized but unused)
125
+ if (typeTasks.length === 0) {
126
+ continue;
127
+ }
128
+ if (taskType === TaskType.Answer) {
129
+ const question = typeTasks[0].action;
130
+ handlers.addToQueue(createAnswerDefinition(question, service));
131
+ }
132
+ else if (taskType === TaskType.Introspect) {
133
+ handlers.addToQueue(createIntrospectDefinition(typeTasks, service));
134
+ }
135
+ else if (taskType === TaskType.Config) {
136
+ // Route to Config flow - extract keys from task params
137
+ const configKeys = typeTasks
138
+ .map((task) => task.params?.key)
139
+ .filter((key) => key !== undefined);
140
+ handlers.addToQueue(createConfigDefinitionWithKeys(configKeys, (config) => {
141
+ // Save config - Config component will handle completion and feedback
142
+ try {
143
+ // Convert flat dotted keys to nested structure grouped by section
144
+ const configBySection = unflattenConfig(config);
145
+ // Save each section
146
+ for (const [section, sectionConfig] of Object.entries(configBySection)) {
147
+ saveConfig(section, sectionConfig);
148
+ }
149
+ }
150
+ catch (error) {
151
+ const errorMessage = error instanceof Error
152
+ ? error.message
153
+ : 'Failed to save configuration';
154
+ throw new Error(errorMessage);
155
+ }
156
+ }, (operation) => {
157
+ handlers.onAborted(operation);
158
+ }));
159
+ }
160
+ else if (taskType === TaskType.Execute) {
161
+ // Execute tasks with validation
106
162
  try {
107
- // Convert flat dotted keys to nested structure grouped by section
108
- const configBySection = unflattenConfig(config);
109
- // Save each section
110
- for (const [section, sectionConfig] of Object.entries(configBySection)) {
111
- saveConfig(section, sectionConfig);
163
+ const validation = validateExecuteTasks(typeTasks);
164
+ if (validation.validationErrors.length > 0) {
165
+ // Show error feedback for invalid skills
166
+ const errorMessages = validation.validationErrors.map((error) => {
167
+ const issuesList = error.issues
168
+ .map((issue) => ` - ${issue}`)
169
+ .join('\n');
170
+ return `Invalid skill definition "${error.skill}":\n\n${issuesList}`;
171
+ });
172
+ handlers.addToQueue(createFeedback(FeedbackType.Failed, errorMessages.join('\n\n')));
173
+ }
174
+ else if (validation.missingConfig.length > 0) {
175
+ handlers.addToQueue(createValidateDefinition(validation.missingConfig, userRequest, service, (error) => {
176
+ handlers.onError(error);
177
+ }, () => {
178
+ handlers.addToQueue(createExecuteDefinition(typeTasks, service));
179
+ }, (operation) => {
180
+ handlers.onAborted(operation);
181
+ }));
182
+ }
183
+ else {
184
+ handlers.addToQueue(createExecuteDefinition(typeTasks, service));
112
185
  }
113
186
  }
114
187
  catch (error) {
115
- const errorMessage = error instanceof Error
116
- ? error.message
117
- : 'Failed to save configuration';
118
- throw new Error(errorMessage);
119
- }
120
- }, (operation) => {
121
- handlers.onAborted(operation);
122
- }));
123
- }
124
- else {
125
- // Execute tasks with validation
126
- try {
127
- const validation = validateExecuteTasks(tasks);
128
- if (validation.validationErrors.length > 0) {
129
- // Show error feedback for invalid skills
130
- const errorMessages = validation.validationErrors.map((error) => {
131
- const issuesList = error.issues
132
- .map((issue) => ` - ${issue}`)
133
- .join('\n');
134
- return `Invalid skill definition "${error.skill}":\n\n${issuesList}`;
135
- });
136
- handlers.addToQueue(createFeedback(FeedbackType.Failed, errorMessages.join('\n\n')));
137
- }
138
- else if (validation.missingConfig.length > 0) {
139
- handlers.addToQueue(createValidateDefinition(validation.missingConfig, userRequest, service, (error) => {
140
- handlers.onError(error);
141
- }, () => {
142
- handlers.addToQueue(createExecuteDefinition(tasks, service));
143
- }, (operation) => {
144
- handlers.onAborted(operation);
145
- }));
188
+ // Handle skill reference errors (e.g., unknown skills)
189
+ const errorMessage = error instanceof Error ? error.message : String(error);
190
+ const message = createMessage(errorMessage);
191
+ handlers.addToQueue(message);
146
192
  }
147
- else {
148
- handlers.addToQueue(createExecuteDefinition(tasks, service));
149
- }
150
- }
151
- catch (error) {
152
- // Handle skill reference errors (e.g., unknown skills)
153
- const errorMessage = error instanceof Error ? error.message : String(error);
154
- const message = createMessage(errorMessage);
155
- handlers.addToQueue(message);
156
193
  }
157
194
  }
158
195
  }
@@ -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 skillsContent = skills.map((s) => s.trim()).join('\n\n');
150
- return header + skillsContent;
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
@@ -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, expandSkillReferences, } from './skills.js';
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 if task originates from a skill
42
- const skillName = typeof task.params?.skill === 'string' ? task.params.skill : null;
43
- if (skillName) {
44
- // Task comes from a skill - check skill's Execution section
45
- const skill = skillLookup(skillName);
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(path)) {
47
+ if (seenPaths.has(configPath)) {
116
48
  continue;
117
49
  }
118
- seenPaths.add(path);
50
+ seenPaths.add(configPath);
119
51
  // Check if config exists
120
- if (!hasConfigPath(userConfig, path)) {
52
+ if (!hasConfigPath(userConfig, configPath)) {
121
53
  missing.push({
122
- path,
54
+ path: configPath,
123
55
  type: 'string', // Default to string for now
124
56
  });
125
57
  }
@@ -3,14 +3,14 @@
3
3
  You are the introspection execution component of "pls" (please), a
4
4
  professional command-line concierge. Your role is to **execute** the listing
5
5
  of available capabilities when a task with type "introspect" has been
6
- planned and confirmed.
6
+ scheduled and confirmed.
7
7
 
8
8
  ## Execution Flow
9
9
 
10
10
  This tool is invoked AFTER:
11
- 1. PLAN detected an introspection request and created a task with type
11
+ 1. SCHEDULE detected an introspection request and created a task with type
12
12
  "introspect"
13
- 2. User reviewed and confirmed the plan
13
+ 2. User reviewed and confirmed the schedule
14
14
  3. The introspect task is now being executed
15
15
 
16
16
  Your task is to present available capabilities in a clear, organized list
@@ -71,7 +71,7 @@ NON-NEGOTIABLE and applies to EVERY response.
71
71
 
72
72
  **DO NOT:**
73
73
  - Reorder capabilities based on alphabetical sorting
74
- - Put Plan or Report first (this is WRONG)
74
+ - Put Schedule or Report first (this is WRONG)
75
75
  - Rearrange based on perceived importance
76
76
  - Deviate from this order for any reason
77
77
 
@@ -90,8 +90,8 @@ These MUST appear FIRST, in this EXACT sequence:
90
90
 
91
91
  These MUST appear AFTER Execute and BEFORE user skills:
92
92
 
93
- 5. **Plan** ← NEVER FIRST, ALWAYS position 5 (after Execute)
94
- 6. **Validate** ← ALWAYS position 6 (after Plan)
93
+ 5. **Schedule** ← NEVER FIRST, ALWAYS position 5 (after Execute)
94
+ 6. **Validate** ← ALWAYS position 6 (after Schedule)
95
95
  7. **Report** ← NEVER FIRST, ALWAYS position 7 (after Validate)
96
96
 
97
97
  ### 3. User-Defined Skills
@@ -113,10 +113,10 @@ Create tasks with type "introspect" for each capability. Each task should:
113
113
  - **Action**: The capability name and a concise description
114
114
  - Format: "Capability Name: description" (note: display format will use
115
115
  " - " separator)
116
- - **IMPORTANT**: Use title case for capability names (e.g., "Plan",
117
- "Execute"), NOT all uppercase (NOT "PLAN", "EXECUTE")
116
+ - **IMPORTANT**: Use title case for capability names (e.g., "Schedule",
117
+ "Execute"), NOT all uppercase (NOT "SCHEDULE", "EXECUTE")
118
118
  - Examples:
119
- - "Plan: break down requests into actionable steps"
119
+ - "Schedule: break down requests into actionable steps"
120
120
  - "Execute: run shell commands and process operations"
121
121
  - "Deploy Application: build and deploy to staging or production"
122
122
  - **Type**: Always use "introspect"
@@ -150,7 +150,7 @@ Examples:
150
150
  When user asks "list your skills", create an introductory message like
151
151
  "here are my capabilities:" followed by tasks for built-in capabilities
152
152
  (Introspect, Config, Answer, Execute), then indirect workflow capabilities
153
- (Plan, Validate, Report).
153
+ (Schedule, Validate, Report).
154
154
 
155
155
  Each task uses type "introspect" with an action describing the
156
156
  capability.
@@ -167,7 +167,7 @@ deploy app skill with its description.
167
167
  When user asks "what can you do" and user-defined skills like "process
168
168
  data" and "backup files" exist, create an introductory message like "i can
169
169
  help with these operations:" followed by all built-in capabilities
170
- (Introspect, Config, Answer, Execute, Validate, Plan, Report) plus the
170
+ (Introspect, Config, Answer, Execute, Validate, Schedule, Report) plus the
171
171
  user-defined skills. Each capability and skill becomes a task with type
172
172
  "introspect".
173
173