prompt-language-shell 0.7.4 → 0.7.8

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
@@ -28,7 +28,7 @@ $ pls list skills
28
28
  Here's what I can help with:
29
29
 
30
30
  - Introspect - list available capabilities and skills
31
- - Config - manage and configure system settings
31
+ - Configure - manage and configure system settings
32
32
  - Answer - respond to questions and provide information
33
33
  - Execute - run shell commands and process operations
34
34
  ```
@@ -74,10 +74,10 @@ Run `pls` without arguments to see the welcome screen.
74
74
  ## How It Works
75
75
 
76
76
  When you make a request, `pls` interprets your intent and creates a structured
77
- plan breaking down the work into individual tasks. You'll see this plan
77
+ plan breaking down the work into individual tasks. You'll see this schedule
78
78
  displayed in your terminal before anything executes.
79
79
 
80
- After reviewing the plan, you can confirm to proceed or cancel if something
80
+ After reviewing the schedule, you can confirm to proceed or cancel if something
81
81
  doesn't look right. Once confirmed, `pls` executes each task sequentially and
82
82
  shows real-time progress and results.
83
83
 
@@ -74,8 +74,8 @@ export class AnthropicService {
74
74
  const skillsSection = formatSkillsForPrompt(skills);
75
75
  systemPrompt += skillsSection;
76
76
  }
77
- // Add config structure for config tool only
78
- if (toolName === 'config') {
77
+ // Add config structure for configure tool only
78
+ if (toolName === 'configure') {
79
79
  const configStructure = getAvailableConfigStructure();
80
80
  const configuredKeys = getConfiguredKeys();
81
81
  const configSection = '\n## Available Configuration\n\n' +
@@ -165,6 +165,7 @@ export class AnthropicService {
165
165
  });
166
166
  return {
167
167
  message: input.message,
168
+ summary: input.summary,
168
169
  tasks: [],
169
170
  commands: input.commands,
170
171
  debug,
@@ -1,5 +1,6 @@
1
1
  import { FeedbackType, TaskType } from '../types/types.js';
2
2
  import { DebugLevel } from './configuration.js';
3
+ import { ExecutionStatus } from './shell.js';
3
4
  /**
4
5
  * Base color palette - raw color values with descriptive names.
5
6
  * All colors used in the interface are defined here.
@@ -210,3 +211,61 @@ export function getTaskTypeLabel(type, debug) {
210
211
  }
211
212
  return type;
212
213
  }
214
+ /**
215
+ * Status icons for execution states
216
+ */
217
+ export const STATUS_ICONS = {
218
+ [ExecutionStatus.Pending]: '- ',
219
+ [ExecutionStatus.Running]: '• ',
220
+ [ExecutionStatus.Success]: '✓ ',
221
+ [ExecutionStatus.Failed]: '✗ ',
222
+ [ExecutionStatus.Aborted]: '⊘ ',
223
+ };
224
+ /**
225
+ * Get colors for different execution status states.
226
+ *
227
+ * Returns color scheme for:
228
+ * - Icon: Status indicator symbol
229
+ * - Description: Task description text
230
+ * - Command: Command text
231
+ * - Symbol: Command prefix symbol
232
+ */
233
+ export function getStatusColors(status) {
234
+ switch (status) {
235
+ case ExecutionStatus.Pending:
236
+ return {
237
+ icon: Palette.Gray,
238
+ description: Palette.Gray,
239
+ command: Palette.DarkGray,
240
+ symbol: Palette.DarkGray,
241
+ };
242
+ case ExecutionStatus.Running:
243
+ return {
244
+ icon: Palette.Gray,
245
+ description: getTextColor(true),
246
+ command: Palette.LightGreen,
247
+ symbol: Palette.AshGray,
248
+ };
249
+ case ExecutionStatus.Success:
250
+ return {
251
+ icon: Colors.Status.Success,
252
+ description: getTextColor(true),
253
+ command: Palette.Gray,
254
+ symbol: Palette.Gray,
255
+ };
256
+ case ExecutionStatus.Failed:
257
+ return {
258
+ icon: Colors.Status.Error,
259
+ description: Colors.Status.Error,
260
+ command: Colors.Status.Error,
261
+ symbol: Palette.Gray,
262
+ };
263
+ case ExecutionStatus.Aborted:
264
+ return {
265
+ icon: Palette.DarkOrange,
266
+ description: getTextColor(true),
267
+ command: Palette.DarkOrange,
268
+ symbol: Palette.Gray,
269
+ };
270
+ }
271
+ }
@@ -361,3 +361,11 @@ export function createValidateDefinition(missingConfig, userRequest, service, on
361
361
  },
362
362
  };
363
363
  }
364
+ /**
365
+ * Add debug components to timeline if present in result
366
+ */
367
+ export function addDebugToTimeline(debugComponents, handlers) {
368
+ if (debugComponents && debugComponents.length > 0 && handlers) {
369
+ handlers.addToTimeline(...debugComponents);
370
+ }
371
+ }
@@ -97,99 +97,121 @@ function executeTasksAfterConfirm(tasks, service, userRequest, handlers) {
97
97
  handlers.onError(error instanceof Error ? error.message : String(error));
98
98
  return;
99
99
  }
100
- // Flatten Group tasks to get actual executable subtasks
101
- const flattenedTasks = [];
102
100
  const scheduledTasks = tasks;
101
+ // Process tasks in order, preserving Group boundaries
102
+ // Track consecutive standalone tasks to group them by type
103
+ let consecutiveStandaloneTasks = [];
104
+ const processStandaloneTasks = () => {
105
+ if (consecutiveStandaloneTasks.length === 0)
106
+ return;
107
+ // Group consecutive standalone tasks by type
108
+ const tasksByType = {};
109
+ for (const type of Object.values(TaskType)) {
110
+ tasksByType[type] = [];
111
+ }
112
+ for (const task of consecutiveStandaloneTasks) {
113
+ tasksByType[task.type].push(task);
114
+ }
115
+ // Route each type group
116
+ for (const [type, typeTasks] of Object.entries(tasksByType)) {
117
+ const taskType = type;
118
+ if (typeTasks.length === 0)
119
+ continue;
120
+ routeTasksByType(taskType, typeTasks, service, userRequest, handlers);
121
+ }
122
+ consecutiveStandaloneTasks = [];
123
+ };
124
+ // Process tasks in original order
103
125
  for (const task of scheduledTasks) {
104
126
  if (task.type === TaskType.Group && task.subtasks) {
105
- // Add all subtasks from the group
106
- flattenedTasks.push(...task.subtasks);
127
+ // Process any accumulated standalone tasks first
128
+ processStandaloneTasks();
129
+ // Process Group as separate component
130
+ if (task.subtasks.length > 0) {
131
+ const subtasks = task.subtasks;
132
+ const taskType = subtasks[0].type;
133
+ routeTasksByType(taskType, subtasks, service, userRequest, handlers);
134
+ }
107
135
  }
108
136
  else {
109
- // Add non-group tasks as-is
110
- flattenedTasks.push(task);
137
+ // Accumulate standalone task
138
+ consecutiveStandaloneTasks.push(task);
111
139
  }
112
140
  }
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] = [];
141
+ // Process any remaining standalone tasks
142
+ processStandaloneTasks();
143
+ }
144
+ /**
145
+ * Route tasks by type to appropriate components
146
+ * Extracted to allow reuse for both Groups and standalone tasks
147
+ */
148
+ function routeTasksByType(taskType, typeTasks, service, userRequest, handlers) {
149
+ if (taskType === TaskType.Answer) {
150
+ // Create separate Answer component for each question
151
+ for (const task of typeTasks) {
152
+ handlers.addToQueue(createAnswerDefinition(task.action, service));
153
+ }
117
154
  }
118
- for (const task of flattenedTasks) {
119
- tasksByType[task.type].push(task);
155
+ else if (taskType === TaskType.Introspect) {
156
+ handlers.addToQueue(createIntrospectDefinition(typeTasks, service));
120
157
  }
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
158
+ else if (taskType === TaskType.Config) {
159
+ // Route to Config flow - extract keys from task params
160
+ const configKeys = typeTasks
161
+ .map((task) => task.params?.key)
162
+ .filter((key) => key !== undefined);
163
+ handlers.addToQueue(createConfigDefinitionWithKeys(configKeys, (config) => {
164
+ // Save config - Config component will handle completion and feedback
162
165
  try {
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));
166
+ // Convert flat dotted keys to nested structure grouped by section
167
+ const configBySection = unflattenConfig(config);
168
+ // Save each section
169
+ for (const [section, sectionConfig] of Object.entries(configBySection)) {
170
+ saveConfig(section, sectionConfig);
185
171
  }
186
172
  }
187
173
  catch (error) {
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);
174
+ const errorMessage = error instanceof Error
175
+ ? error.message
176
+ : 'Failed to save configuration';
177
+ throw new Error(errorMessage);
192
178
  }
179
+ }, (operation) => {
180
+ handlers.onAborted(operation);
181
+ }));
182
+ }
183
+ else if (taskType === TaskType.Execute) {
184
+ // Execute tasks with validation
185
+ try {
186
+ const validation = validateExecuteTasks(typeTasks);
187
+ if (validation.validationErrors.length > 0) {
188
+ // Show error feedback for invalid skills
189
+ const errorMessages = validation.validationErrors.map((error) => {
190
+ const issuesList = error.issues
191
+ .map((issue) => ` - ${issue}`)
192
+ .join('\n');
193
+ return `Invalid skill definition "${error.skill}":\n\n${issuesList}`;
194
+ });
195
+ handlers.addToQueue(createFeedback(FeedbackType.Failed, errorMessages.join('\n\n')));
196
+ }
197
+ else if (validation.missingConfig.length > 0) {
198
+ handlers.addToQueue(createValidateDefinition(validation.missingConfig, userRequest, service, (error) => {
199
+ handlers.onError(error);
200
+ }, () => {
201
+ handlers.addToQueue(createExecuteDefinition(typeTasks, service));
202
+ }, (operation) => {
203
+ handlers.onAborted(operation);
204
+ }));
205
+ }
206
+ else {
207
+ handlers.addToQueue(createExecuteDefinition(typeTasks, service));
208
+ }
209
+ }
210
+ catch (error) {
211
+ // Handle skill reference errors (e.g., unknown skills)
212
+ const errorMessage = error instanceof Error ? error.message : String(error);
213
+ const message = createMessage(errorMessage);
214
+ handlers.addToQueue(message);
193
215
  }
194
216
  }
195
217
  }
@@ -7,10 +7,10 @@ import { parseSkillMarkdown, displayNameToKey } from './parser.js';
7
7
  * Built-in skill names that user skills cannot override
8
8
  */
9
9
  const BUILT_IN_SKILLS = new Set([
10
- 'plan',
10
+ 'schedule',
11
11
  'execute',
12
12
  'answer',
13
- 'config',
13
+ 'configure',
14
14
  'validate',
15
15
  'introspect',
16
16
  ]);
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Calculates elapsed time from a start timestamp, rounded to seconds.
3
+ */
4
+ export function calculateElapsed(start) {
5
+ return Math.floor((Date.now() - start) / 1000) * 1000;
6
+ }
1
7
  /**
2
8
  * Formats a duration in milliseconds to a human-readable string.
3
9
  * Uses correct singular/plural forms.
@@ -13,8 +13,8 @@ training data.
13
13
  ## Execution Flow
14
14
 
15
15
  This tool is invoked AFTER:
16
- 1. PLAN detected an information request and created a task with type "answer"
17
- 2. User reviewed and confirmed the plan
16
+ 1. SCHEDULE detected an information request and created a task with type "answer"
17
+ 2. User reviewed and confirmed the schedule
18
18
  3. The answer task is now being executed
19
19
 
20
20
  Your task is to provide a clear, concise answer to the user's question.
@@ -7,11 +7,11 @@ operations when tasks with type "execute" have been planned and confirmed.
7
7
  ## Execution Flow
8
8
 
9
9
  This tool is invoked AFTER:
10
- 1. PLAN created tasks with type "execute" describing operations to perform
11
- 2. User reviewed and confirmed the plan
10
+ 1. SCHEDULE created tasks with type "execute" describing operations to perform
11
+ 2. User reviewed and confirmed the schedule
12
12
  3. The execute tasks are now being executed
13
13
 
14
- Your task is to translate the planned actions into specific shell commands
14
+ Your task is to translate the scheduled actions into specific shell commands
15
15
  that can be run in the terminal.
16
16
 
17
17
  ## Input
@@ -88,7 +88,12 @@ these commands specifically for their environment and workflow.
88
88
  Return a structured response with commands to execute:
89
89
 
90
90
  **Response structure:**
91
- - **message**: Brief status message (max 64 characters, end with period)
91
+ - **message**: Brief status message in imperative mood (max 64 characters,
92
+ end with colon)
93
+ - **summary**: Natural language summary as if execution has finished,
94
+ like a concierge would report (max 48 characters, no period, time will
95
+ be appended). Use varied expressions and synonyms, not necessarily the
96
+ same verb as the message. MUST NOT be empty.
92
97
  - **commands**: Array of command objects to execute sequentially
93
98
 
94
99
  **Command object structure:**
@@ -133,7 +138,8 @@ Task: {
133
138
 
134
139
  Response:
135
140
  ```
136
- message: "Creating the file."
141
+ message: "Create the file:"
142
+ summary: "File created"
137
143
  commands:
138
144
  - description: "Create test.txt"
139
145
  command: "touch test.txt"
@@ -148,7 +154,8 @@ Task: {
148
154
 
149
155
  Response:
150
156
  ```
151
- message: "Listing directory contents."
157
+ message: "List directory contents:"
158
+ summary: "I've listed the directory contents"
152
159
  commands:
153
160
  - description: "List files with details"
154
161
  command: "ls -la"
@@ -167,7 +174,8 @@ Tasks:
167
174
 
168
175
  Response:
169
176
  ```
170
- message: "Setting up the project."
177
+ message: "Set up the project:"
178
+ summary: "Project ready to go"
171
179
  commands:
172
180
  - description: "Create project directory"
173
181
  command: "mkdir -p my-project"
@@ -188,7 +196,8 @@ Task: {
188
196
 
189
197
  Response:
190
198
  ```
191
- message: "Installing dependencies."
199
+ message: "Install dependencies:"
200
+ summary: "Dependencies installed successfully"
192
201
  commands:
193
202
  - description: "Install npm packages"
194
203
  command: "npm install"
@@ -224,7 +233,8 @@ The "Process Data" skill's Execution section specifies:
224
233
 
225
234
  Response (using skill's Execution commands):
226
235
  ```
227
- message: "Processing sales data."
236
+ message: "Process sales data:"
237
+ summary: "Sales data transformed and exported"
228
238
  commands:
229
239
  - description: "Load the sales dataset"
230
240
  command: "curl -O https://data.example.com/sales.csv"
@@ -250,7 +260,8 @@ Task: {
250
260
 
251
261
  Response:
252
262
  ```
253
- message: "Creating backup."
263
+ message: "Create backup:"
264
+ summary: "Backup complete"
254
265
  commands:
255
266
  - description: "Copy config directory"
256
267
  command: "cp -r ~/.config/app ~/.config/app.backup"
@@ -265,7 +276,8 @@ Task: {
265
276
 
266
277
  Response:
267
278
  ```
268
- message: "Checking disk space."
279
+ message: "Check disk space:"
280
+ summary: "Disk space verified"
269
281
  commands:
270
282
  - description: "Show disk usage"
271
283
  command: "df -h"
@@ -82,7 +82,7 @@ NON-NEGOTIABLE and applies to EVERY response.
82
82
  These MUST appear FIRST, in this EXACT sequence:
83
83
 
84
84
  1. **Introspect** ← ALWAYS FIRST
85
- 2. **Config** ← ALWAYS SECOND
85
+ 2. **Configure** ← ALWAYS SECOND
86
86
  3. **Answer** ← ALWAYS THIRD
87
87
  4. **Execute** ← ALWAYS FOURTH
88
88
 
@@ -149,7 +149,7 @@ Examples:
149
149
 
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
- (Introspect, Config, Answer, Execute), then indirect workflow capabilities
152
+ (Introspect, Configure, Answer, Execute), then indirect workflow capabilities
153
153
  (Schedule, Validate, Report).
154
154
 
155
155
  Each task uses type "introspect" with an action describing the
@@ -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, Schedule, Report) plus the
170
+ (Introspect, Configure, 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
 
@@ -7,13 +7,17 @@ task structures with high-level tasks and their subtasks.
7
7
  ## Response Format
8
8
 
9
9
  Every response MUST include a brief message (single sentence, max 64
10
- characters, ending with period) that introduces the schedule.
10
+ characters, ending with period) that introduces the schedule. Use
11
+ either imperative mood or present tense statements, but NEVER use
12
+ present continuous ("-ing" form).
11
13
 
12
- **Examples**: "Here's the schedule." / "I've organized the work." /
13
- "This is how I'll structure it."
14
+ **Examples**: "Build the application." / "Here's the schedule." /
15
+ "Deploy to production." / "I've organized the work."
14
16
 
15
17
  **Critical rules**:
16
18
  - Message is MANDATORY
19
+ - Use imperative mood OR present tense statements
20
+ - NEVER use present continuous ("-ing" form)
17
21
  - NEVER repeat the same message
18
22
  - ALWAYS end with period (.)
19
23
  - Vary phrasing naturally
@@ -56,6 +60,14 @@ Every task MUST have a type field. Use the appropriate type:
56
60
  a matching skill in the "Available Skills" section. DO NOT create
57
61
  `execute` tasks without a corresponding skill.
58
62
 
63
+ **Define task params**: When creating a `define` type task, include:
64
+ - `skill`: the skill name that needs variant selection (REQUIRED)
65
+ - `options`: array of option strings describing each variant (REQUIRED)
66
+
67
+ Example: User "build" without variant → Task with type "define",
68
+ params { skill: "Build Project", options: ["Build project Alpha, the
69
+ main variant", "Build project Beta, the experimental variant"] }
70
+
59
71
  ## Configuration Requests
60
72
 
61
73
  When user wants to configure or change settings (e.g., "config",
@@ -130,12 +142,15 @@ components (e.g., {project.VARIANT.path}, {env.TYPE.config},
130
142
 
131
143
  5. **Extract config expressions**: All leaf tasks must include a
132
144
  `config` array listing resolved configuration paths:
133
- - After resolving variant placeholders, extract all config
134
- expressions from the task's execution commands
145
+ - After resolving variant placeholders, extract **ALL** config
146
+ expressions from the task's execution commands (every single
147
+ placeholder in curly braces)
135
148
  - List them in dot notation (e.g., "project.beta.repo",
136
149
  "env.production.url")
137
150
  - The app will check if these exist in ~/.plsrc and prompt for
138
151
  missing values
152
+ - **CRITICAL**: If a task has multiple config placeholders, ALL
153
+ must be included in the config array
139
154
  - Example: Task with `cd {project.beta.repo}` and `cat
140
155
  {project.beta.config}` should include config:
141
156
  ["project.beta.repo", "project.beta.config"]
@@ -193,27 +208,51 @@ structure.
193
208
 
194
209
  ## Sequential and Multiple Requests
195
210
 
196
- When the user provides multiple requests separated by commas,
197
- semicolons, or the word "and":
211
+ **CRITICAL**: When the user provides multiple requests separated by
212
+ commas, semicolons, or the word "and", EVERY request must be
213
+ represented as a separate task. DO NOT skip or merge any requests,
214
+ even if they use the same action verb.
215
+
216
+ **Sequential Processing Rules:**
217
+
218
+ 1. **Preserve ALL requests**: Each operation in the sequence creates a
219
+ separate task, in the exact order specified. Count the requests
220
+ carefully and verify each one is represented.
221
+
222
+ 2. **Same action, different subjects = separate tasks**: Multiple
223
+ requests using the same verb with different subjects are NOT
224
+ duplicates:
225
+ - "explain X, explain Y" → TWO separate answer tasks
226
+ - "process A, process B" → TWO separate task groups
227
+ - "show X, show Y" → TWO separate report/answer tasks
198
228
 
199
- 1. **Preserve the sequence**: Each operation should be represented as a
200
- separate task in the order specified
201
- 2. **Independent skill matching**: For each operation, independently
229
+ 3. **Independent skill matching**: For each operation, independently
202
230
  check if it matches a skill:
203
231
  - If operation matches a skill → extract skill steps as subtasks
204
232
  - If operation does NOT match a skill → create "ignore" type task
205
233
  - **CRITICAL: Do NOT infer context or create generic execute tasks
206
234
  for unmatched operations**
207
- 3. **No merging**: Keep operations separate even if they seem related.
208
- The user's sequence is intentional.
235
+
236
+ 4. **No merging**: Keep operations separate even if they seem related.
237
+ The user's sequence is intentional and must be preserved exactly.
238
+
239
+ 5. **Verify completeness**: Before finalizing, count your tasks and
240
+ verify the count matches the number of distinct requests in the
241
+ user's input.
209
242
 
210
243
  **Examples:**
211
244
 
212
- - "explain docker, build production, then list the changes" → Three
213
- separate task groups:
245
+ - "explain docker, process data, explain kubernetes" → THREE
246
+ separate task groups (not two):
214
247
  - Task 1: "Explain Docker" (type: answer)
215
- - Task 2: "Build production" (skill-based with subtasks)
216
- - Task 3: "List the changes" (type: answer or report)
248
+ - Task 2: "Process data" (skill-based with subtasks)
249
+ - Task 3: "Explain Kubernetes" (type: answer)
250
+
251
+ - "explain tdd, process files, explain tbd" → THREE separate task
252
+ groups:
253
+ - Task 1: "Explain Test-Driven Development" (type: answer)
254
+ - Task 2: "Process files" (skill-based with subtasks)
255
+ - Task 3: "Explain TBD" (type: answer)
217
256
 
218
257
  - "process files and validate" where only "process" has a skill →
219
258
  - Task 1: "Process files" (skill-based with subtasks)
@@ -270,14 +309,20 @@ Before finalizing, verify there are no duplicates.
270
309
  simple terms")
271
310
  - "list X completely" = ONE task (not "list X" + "be complete")
272
311
 
273
- 2. **Synonymous verbs are duplicates**: Different verbs meaning the
274
- same thing are duplicates
312
+ 2. **Synonymous verbs with SAME subject are duplicates**: Different
313
+ verbs meaning the same thing on the SAME subject are duplicates
275
314
  - "explain X" + "describe X" = DUPLICATE (choose one)
276
315
  - "show X" + "display X" = DUPLICATE (choose one)
277
316
  - "check X" + "verify X" = DUPLICATE (choose one)
278
317
 
279
- 3. **Redundant operations are duplicates**: If two tasks would perform
280
- the same operation
318
+ 3. **Same verb with DIFFERENT subjects are NOT duplicates**: This is
319
+ a sequential request and each must be preserved
320
+ - "explain X" + "explain Y" = TWO SEPARATE TASKS
321
+ - "process A" + "process B" = TWO SEPARATE TASKS
322
+ - "show X" + "show Y" = TWO SEPARATE TASKS
323
+
324
+ 4. **Redundant operations are duplicates**: If two tasks would perform
325
+ the same operation on the same target
281
326
  - "install and set up dependencies" = ONE task (setup is part of
282
327
  install)
283
328
  - "check and verify disk space" = ONE task (verify means check)
@@ -286,17 +331,22 @@ Before finalizing, verify there are no duplicates.
286
331
 
287
332
  Before finalizing the schedule, perform strict validation:
288
333
 
289
- 1. Each task represents a distinct step in the user's request
290
- 2. Tasks are ordered in the logical sequence they should execute
291
- 3. Each task is clearly defined with specific action and parameters
292
- 4. Tasks are NOT merged - preserve the user's intended sequence
293
- 5. All operations from the user's request are represented
294
- 6. No semantic duplicates exist (same operation with different words)
295
- 7. For skill-based tasks, verify all required params are included
334
+ 1. **Count verification**: Count the distinct requests in the user's
335
+ input and verify your task list has the same number of top-level
336
+ tasks. If counts don't match, you've skipped or merged requests.
337
+ 2. Each task represents a distinct step in the user's request
338
+ 3. Tasks are ordered in the logical sequence they should execute
339
+ 4. Each task is clearly defined with specific action and parameters
340
+ 5. Tasks are NOT merged - preserve the user's intended sequence
341
+ 6. All operations from the user's request are represented (check each
342
+ one individually)
343
+ 7. No semantic duplicates exist (same verb on same subject), but same
344
+ verb on different subjects creates separate tasks
345
+ 8. For skill-based tasks, verify all required params are included
296
346
  (skill name, variant if applicable)
297
- 8. For leaf tasks, verify type field is present
298
- 9. For leaf tasks with config placeholders, verify config array is
299
- populated
347
+ 9. For leaf tasks, verify type field is present
348
+ 10. For leaf tasks with config placeholders, verify config array is
349
+ populated
300
350
 
301
351
  ## Critical Guidelines
302
352