prompt-language-shell 0.9.0 → 0.9.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/dist/{ui/Main.js → Main.js} +24 -17
- package/dist/{ui → components}/Component.js +31 -26
- package/dist/{ui → components}/Workflow.js +23 -7
- package/dist/{ui → components/controllers}/Answer.js +18 -17
- package/dist/{ui → components/controllers}/Command.js +21 -24
- package/dist/{ui → components/controllers}/Config.js +17 -119
- package/dist/components/controllers/Confirm.js +42 -0
- package/dist/components/controllers/Execute.js +288 -0
- package/dist/{ui → components/controllers}/Introspect.js +22 -39
- package/dist/components/controllers/Refinement.js +18 -0
- package/dist/{ui → components/controllers}/Schedule.js +8 -124
- package/dist/{ui → components/controllers}/Validate.js +37 -50
- package/dist/components/views/Answer.js +28 -0
- package/dist/components/views/Command.js +11 -0
- package/dist/components/views/Config.js +115 -0
- package/dist/components/views/Confirm.js +24 -0
- package/dist/components/views/Execute.js +60 -0
- package/dist/{ui → components/views}/Feedback.js +3 -3
- package/dist/components/views/Introspect.js +17 -0
- package/dist/{ui → components/views}/Label.js +3 -3
- package/dist/{ui → components/views}/List.js +3 -3
- package/dist/{ui → components/views}/Output.js +2 -2
- package/dist/components/views/Refinement.js +9 -0
- package/dist/{ui → components/views}/Report.js +1 -1
- package/dist/components/views/Schedule.js +120 -0
- package/dist/{ui → components/views}/Separator.js +1 -1
- package/dist/{ui → components/views}/Spinner.js +1 -1
- package/dist/{ui → components/views}/Subtask.js +10 -7
- package/dist/components/views/Task.js +18 -0
- package/dist/components/views/Upcoming.js +30 -0
- package/dist/{ui → components/views}/UserQuery.js +1 -1
- package/dist/components/views/Validate.js +17 -0
- package/dist/{ui → components/views}/Welcome.js +1 -1
- package/dist/{services/config-labels.js → configuration/labels.js} +1 -1
- package/dist/configuration/schema.js +2 -2
- package/dist/configuration/steps.js +171 -0
- package/dist/configuration/transformation.js +17 -0
- package/dist/execution/handlers.js +20 -60
- package/dist/execution/processing.js +3 -1
- package/dist/execution/reducer.js +34 -44
- package/dist/execution/runner.js +99 -0
- package/dist/execution/types.js +4 -4
- package/dist/execution/utils.js +23 -1
- package/dist/index.js +1 -1
- package/dist/services/components.js +109 -394
- package/dist/services/logger.js +3 -3
- package/dist/services/messages.js +19 -0
- package/dist/services/refinement.js +5 -2
- package/dist/services/router.js +136 -55
- package/dist/services/shell.js +26 -6
- package/dist/services/timing.js +1 -0
- package/dist/skills/execute.md +40 -14
- package/dist/tools/execute.tool.js +0 -4
- package/dist/types/schemas.js +0 -1
- package/package.json +1 -1
- package/dist/parser.js +0 -13
- package/dist/services/config-utils.js +0 -20
- package/dist/ui/Confirm.js +0 -62
- package/dist/ui/Execute.js +0 -294
- package/dist/ui/Refinement.js +0 -23
- package/dist/ui/Task.js +0 -175
- /package/dist/{ui → components/views}/Debug.js +0 -0
- /package/dist/{ui → components/views}/Message.js +0 -0
- /package/dist/{ui → components/views}/Panel.js +0 -0
package/dist/services/router.js
CHANGED
|
@@ -2,10 +2,11 @@ import { asScheduledTasks } from '../types/guards.js';
|
|
|
2
2
|
import { FeedbackType, TaskType } from '../types/types.js';
|
|
3
3
|
import { saveConfig } from '../configuration/io.js';
|
|
4
4
|
import { getConfigSchema } from '../configuration/schema.js';
|
|
5
|
+
import { createConfigStepsFromSchema } from '../configuration/steps.js';
|
|
5
6
|
import { unflattenConfig } from '../configuration/transformation.js';
|
|
6
|
-
import { saveConfigLabels } from '
|
|
7
|
-
import {
|
|
8
|
-
import { getCancellationMessage, getMixedTaskTypesError, getUnknownRequestMessage, } from './messages.js';
|
|
7
|
+
import { saveConfigLabels } from '../configuration/labels.js';
|
|
8
|
+
import { createAnswer, createConfig, createConfirm, createExecute, createFeedback, createIntrospect, createMessage, createSchedule, createValidate, } from './components.js';
|
|
9
|
+
import { getCancellationMessage, getConfirmationMessage, getMixedTaskTypesError, getUnknownRequestMessage, } from './messages.js';
|
|
9
10
|
import { validateExecuteTasks } from './validator.js';
|
|
10
11
|
/**
|
|
11
12
|
* Determine the operation name based on task types
|
|
@@ -30,7 +31,7 @@ export function routeTasksWithConfirm(tasks, message, service, userRequest, life
|
|
|
30
31
|
const validTasks = tasks.filter((task) => task.type !== TaskType.Ignore && task.type !== TaskType.Discard);
|
|
31
32
|
// Check if no valid tasks remain after filtering
|
|
32
33
|
if (validTasks.length === 0) {
|
|
33
|
-
const msg = createMessage(getUnknownRequestMessage());
|
|
34
|
+
const msg = createMessage({ text: getUnknownRequestMessage() });
|
|
34
35
|
workflowHandlers.addToQueue(msg);
|
|
35
36
|
return;
|
|
36
37
|
}
|
|
@@ -45,7 +46,7 @@ export function routeTasksWithConfirm(tasks, message, service, userRequest, life
|
|
|
45
46
|
if (hasDefineTask) {
|
|
46
47
|
// Has DEFINE tasks - add Schedule to queue for user selection
|
|
47
48
|
// Refinement flow will call this function again with refined tasks
|
|
48
|
-
const scheduleDefinition =
|
|
49
|
+
const scheduleDefinition = createSchedule({ message, tasks: validTasks });
|
|
49
50
|
workflowHandlers.addToQueue(scheduleDefinition);
|
|
50
51
|
}
|
|
51
52
|
else {
|
|
@@ -53,19 +54,27 @@ export function routeTasksWithConfirm(tasks, message, service, userRequest, life
|
|
|
53
54
|
// When Schedule activates, Command moves to timeline
|
|
54
55
|
// When Schedule completes, it moves to pending
|
|
55
56
|
// When Confirm activates, Schedule stays pending (visible for context)
|
|
56
|
-
const scheduleDefinition =
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
57
|
+
const scheduleDefinition = createSchedule({
|
|
58
|
+
message,
|
|
59
|
+
tasks: validTasks,
|
|
60
|
+
onSelectionConfirmed: () => {
|
|
61
|
+
// Schedule completed - add Confirm to queue
|
|
62
|
+
const confirmDefinition = createConfirm({
|
|
63
|
+
message: getConfirmationMessage(),
|
|
64
|
+
onConfirmed: () => {
|
|
65
|
+
// User confirmed - complete both Confirm and Schedule, then route
|
|
66
|
+
lifecycleHandlers.completeActiveAndPending();
|
|
67
|
+
executeTasksAfterConfirm(validTasks, context);
|
|
68
|
+
},
|
|
69
|
+
onCancelled: () => {
|
|
70
|
+
// User cancelled - complete both Confirm and Schedule, then show cancellation
|
|
71
|
+
lifecycleHandlers.completeActiveAndPending();
|
|
72
|
+
const message = getCancellationMessage(operation);
|
|
73
|
+
workflowHandlers.addToQueue(createFeedback({ type: FeedbackType.Aborted, message }));
|
|
74
|
+
},
|
|
75
|
+
});
|
|
76
|
+
workflowHandlers.addToQueue(confirmDefinition);
|
|
77
|
+
},
|
|
69
78
|
});
|
|
70
79
|
workflowHandlers.addToQueue(scheduleDefinition);
|
|
71
80
|
}
|
|
@@ -134,18 +143,28 @@ function executeTasksAfterConfirm(tasks, context) {
|
|
|
134
143
|
.join('\n');
|
|
135
144
|
return `Invalid skill definition "${error.skill}":\n\n${issuesList}`;
|
|
136
145
|
});
|
|
137
|
-
workflowHandlers.addToQueue(createFeedback(
|
|
146
|
+
workflowHandlers.addToQueue(createFeedback({
|
|
147
|
+
type: FeedbackType.Failed,
|
|
148
|
+
message: errorMessages.join('\n\n'),
|
|
149
|
+
}));
|
|
138
150
|
return;
|
|
139
151
|
}
|
|
140
152
|
else if (validation.missingConfig.length > 0) {
|
|
141
153
|
// Missing config detected - create ONE Validate component for ALL missing config
|
|
142
|
-
workflowHandlers.addToQueue(
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
154
|
+
workflowHandlers.addToQueue(createValidate({
|
|
155
|
+
missingConfig: validation.missingConfig,
|
|
156
|
+
userRequest,
|
|
157
|
+
service,
|
|
158
|
+
onError: (error) => {
|
|
159
|
+
requestHandlers.onError(error);
|
|
160
|
+
},
|
|
161
|
+
onValidationComplete: () => {
|
|
162
|
+
// After config is complete, resume task routing
|
|
163
|
+
routeTasksAfterConfig(scheduledTasks, context);
|
|
164
|
+
},
|
|
165
|
+
onAborted: (operation) => {
|
|
166
|
+
requestHandlers.onAborted(operation);
|
|
167
|
+
},
|
|
149
168
|
}));
|
|
150
169
|
return;
|
|
151
170
|
}
|
|
@@ -158,11 +177,37 @@ function executeTasksAfterConfirm(tasks, context) {
|
|
|
158
177
|
// No missing config - proceed with normal routing
|
|
159
178
|
routeTasksAfterConfig(scheduledTasks, context);
|
|
160
179
|
}
|
|
180
|
+
/**
|
|
181
|
+
* Task types that should appear in the upcoming display
|
|
182
|
+
*/
|
|
183
|
+
const UPCOMING_TASK_TYPES = [TaskType.Execute, TaskType.Answer];
|
|
184
|
+
/**
|
|
185
|
+
* Collect names of all upcoming execution units (groups and standalone tasks)
|
|
186
|
+
* for display during task execution
|
|
187
|
+
*/
|
|
188
|
+
function collectUpcomingNames(scheduledTasks) {
|
|
189
|
+
const names = [];
|
|
190
|
+
for (const task of scheduledTasks) {
|
|
191
|
+
if (task.type === TaskType.Group && task.subtasks?.length) {
|
|
192
|
+
const subtasks = task.subtasks;
|
|
193
|
+
if (UPCOMING_TASK_TYPES.includes(subtasks[0].type)) {
|
|
194
|
+
names.push(task.action);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
else if (UPCOMING_TASK_TYPES.includes(task.type)) {
|
|
198
|
+
names.push(task.action);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
return names;
|
|
202
|
+
}
|
|
161
203
|
/**
|
|
162
204
|
* Route tasks after config is complete (or when no config is needed)
|
|
163
205
|
* Processes tasks in order, grouping by type
|
|
164
206
|
*/
|
|
165
207
|
function routeTasksAfterConfig(scheduledTasks, context) {
|
|
208
|
+
// Collect all unit names for upcoming display
|
|
209
|
+
const allUnitNames = collectUpcomingNames(scheduledTasks);
|
|
210
|
+
let currentUnitIndex = 0;
|
|
166
211
|
// Process tasks in order, preserving Group boundaries
|
|
167
212
|
// Track consecutive standalone tasks to group them by type
|
|
168
213
|
let consecutiveStandaloneTasks = [];
|
|
@@ -182,7 +227,18 @@ function routeTasksAfterConfig(scheduledTasks, context) {
|
|
|
182
227
|
const taskType = type;
|
|
183
228
|
if (typeTasks.length === 0)
|
|
184
229
|
continue;
|
|
185
|
-
|
|
230
|
+
// For tasks that appear in upcoming, calculate from remaining units
|
|
231
|
+
if (UPCOMING_TASK_TYPES.includes(taskType)) {
|
|
232
|
+
// Each task advances the unit index
|
|
233
|
+
for (const task of typeTasks) {
|
|
234
|
+
const upcoming = allUnitNames.slice(currentUnitIndex + 1);
|
|
235
|
+
currentUnitIndex++;
|
|
236
|
+
routeTasksByType(taskType, [task], context, upcoming);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
else {
|
|
240
|
+
routeTasksByType(taskType, typeTasks, context, []);
|
|
241
|
+
}
|
|
186
242
|
}
|
|
187
243
|
consecutiveStandaloneTasks = [];
|
|
188
244
|
};
|
|
@@ -195,7 +251,20 @@ function routeTasksAfterConfig(scheduledTasks, context) {
|
|
|
195
251
|
if (task.subtasks.length > 0) {
|
|
196
252
|
const subtasks = task.subtasks;
|
|
197
253
|
const taskType = subtasks[0].type;
|
|
198
|
-
|
|
254
|
+
// Calculate upcoming (all units after this one)
|
|
255
|
+
const upcoming = UPCOMING_TASK_TYPES.includes(taskType)
|
|
256
|
+
? allUnitNames.slice(currentUnitIndex + 1)
|
|
257
|
+
: [];
|
|
258
|
+
if (UPCOMING_TASK_TYPES.includes(taskType)) {
|
|
259
|
+
currentUnitIndex++;
|
|
260
|
+
}
|
|
261
|
+
// Pass group name as label for Execute groups
|
|
262
|
+
if (taskType === TaskType.Execute) {
|
|
263
|
+
routeExecuteTasks(subtasks, context, upcoming, task.action);
|
|
264
|
+
}
|
|
265
|
+
else {
|
|
266
|
+
routeTasksByType(taskType, subtasks, context, upcoming);
|
|
267
|
+
}
|
|
199
268
|
}
|
|
200
269
|
}
|
|
201
270
|
else {
|
|
@@ -209,21 +278,29 @@ function routeTasksAfterConfig(scheduledTasks, context) {
|
|
|
209
278
|
/**
|
|
210
279
|
* Route Answer tasks - creates separate Answer component for each question
|
|
211
280
|
*/
|
|
212
|
-
function routeAnswerTasks(tasks, context) {
|
|
213
|
-
for (
|
|
214
|
-
|
|
281
|
+
function routeAnswerTasks(tasks, context, upcoming) {
|
|
282
|
+
for (let i = 0; i < tasks.length; i++) {
|
|
283
|
+
const task = tasks[i];
|
|
284
|
+
// Calculate upcoming: remaining answer tasks + original upcoming
|
|
285
|
+
const remainingAnswers = tasks.slice(i + 1).map((t) => t.action);
|
|
286
|
+
const taskUpcoming = [...remainingAnswers, ...upcoming];
|
|
287
|
+
context.workflowHandlers.addToQueue(createAnswer({
|
|
288
|
+
question: task.action,
|
|
289
|
+
service: context.service,
|
|
290
|
+
upcoming: taskUpcoming,
|
|
291
|
+
}));
|
|
215
292
|
}
|
|
216
293
|
}
|
|
217
294
|
/**
|
|
218
295
|
* Route Introspect tasks - creates single Introspect component for all tasks
|
|
219
296
|
*/
|
|
220
|
-
function routeIntrospectTasks(tasks, context) {
|
|
221
|
-
context.workflowHandlers.addToQueue(
|
|
297
|
+
function routeIntrospectTasks(tasks, context, _upcoming) {
|
|
298
|
+
context.workflowHandlers.addToQueue(createIntrospect({ tasks, service: context.service }));
|
|
222
299
|
}
|
|
223
300
|
/**
|
|
224
301
|
* Route Config tasks - extracts keys, caches labels, creates Config component
|
|
225
302
|
*/
|
|
226
|
-
function routeConfigTasks(tasks, context) {
|
|
303
|
+
function routeConfigTasks(tasks, context, _upcoming) {
|
|
227
304
|
const configKeys = tasks
|
|
228
305
|
.map((task) => task.params?.key)
|
|
229
306
|
.filter((key) => key !== undefined);
|
|
@@ -240,31 +317,35 @@ function routeConfigTasks(tasks, context) {
|
|
|
240
317
|
if (Object.keys(labels).length > 0) {
|
|
241
318
|
saveConfigLabels(labels);
|
|
242
319
|
}
|
|
243
|
-
context.workflowHandlers.addToQueue(
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
//
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
320
|
+
context.workflowHandlers.addToQueue(createConfig({
|
|
321
|
+
steps: createConfigStepsFromSchema(configKeys),
|
|
322
|
+
onFinished: (config) => {
|
|
323
|
+
// Save config - Config component will handle completion and feedback
|
|
324
|
+
try {
|
|
325
|
+
// Convert flat dotted keys to nested structure grouped by section
|
|
326
|
+
const configBySection = unflattenConfig(config);
|
|
327
|
+
// Save each section
|
|
328
|
+
for (const [section, sectionConfig] of Object.entries(configBySection)) {
|
|
329
|
+
saveConfig(section, sectionConfig);
|
|
330
|
+
}
|
|
251
331
|
}
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
|
|
332
|
+
catch (error) {
|
|
333
|
+
const errorMessage = error instanceof Error
|
|
334
|
+
? error.message
|
|
335
|
+
: 'Failed to save configuration';
|
|
336
|
+
throw new Error(errorMessage);
|
|
337
|
+
}
|
|
338
|
+
},
|
|
339
|
+
onAborted: (operation) => {
|
|
340
|
+
context.requestHandlers.onAborted(operation);
|
|
341
|
+
},
|
|
261
342
|
}));
|
|
262
343
|
}
|
|
263
344
|
/**
|
|
264
345
|
* Route Execute tasks - creates Execute component (validation already done)
|
|
265
346
|
*/
|
|
266
|
-
function routeExecuteTasks(tasks, context) {
|
|
267
|
-
context.workflowHandlers.addToQueue(
|
|
347
|
+
function routeExecuteTasks(tasks, context, upcoming, label) {
|
|
348
|
+
context.workflowHandlers.addToQueue(createExecute({ tasks, service: context.service, upcoming, label }));
|
|
268
349
|
}
|
|
269
350
|
/**
|
|
270
351
|
* Registry mapping task types to their route handlers
|
|
@@ -279,9 +360,9 @@ const taskRouteHandlers = {
|
|
|
279
360
|
* Route tasks by type to appropriate components
|
|
280
361
|
* Uses registry pattern for extensibility
|
|
281
362
|
*/
|
|
282
|
-
function routeTasksByType(taskType, tasks, context) {
|
|
363
|
+
function routeTasksByType(taskType, tasks, context, upcoming) {
|
|
283
364
|
const handler = taskRouteHandlers[taskType];
|
|
284
365
|
if (handler) {
|
|
285
|
-
handler(tasks, context);
|
|
366
|
+
handler(tasks, context, upcoming);
|
|
286
367
|
}
|
|
287
368
|
}
|
package/dist/services/shell.js
CHANGED
|
@@ -61,6 +61,14 @@ export class DummyExecutor {
|
|
|
61
61
|
}
|
|
62
62
|
// Marker for extracting pwd from command output
|
|
63
63
|
const PWD_MARKER = '__PWD_MARKER_7x9k2m__';
|
|
64
|
+
const MAX_OUTPUT_LINES = 128;
|
|
65
|
+
/**
|
|
66
|
+
* Limit output to last MAX_OUTPUT_LINES lines.
|
|
67
|
+
*/
|
|
68
|
+
function limitLines(output) {
|
|
69
|
+
const lines = output.split('\n');
|
|
70
|
+
return lines.slice(-MAX_OUTPUT_LINES).join('\n');
|
|
71
|
+
}
|
|
64
72
|
/**
|
|
65
73
|
* Parse stdout to extract workdir and clean output.
|
|
66
74
|
* Returns the cleaned output and the extracted workdir.
|
|
@@ -93,6 +101,12 @@ class OutputStreamer {
|
|
|
93
101
|
*/
|
|
94
102
|
pushStdout(data) {
|
|
95
103
|
this.chunks.push(data);
|
|
104
|
+
// Collapse when we have too many chunks to prevent memory growth
|
|
105
|
+
if (this.chunks.length > 16) {
|
|
106
|
+
const accumulated = this.chunks.join('');
|
|
107
|
+
this.chunks = [limitLines(accumulated)];
|
|
108
|
+
this.emittedLength = 0;
|
|
109
|
+
}
|
|
96
110
|
if (!this.callback)
|
|
97
111
|
return;
|
|
98
112
|
const accumulated = this.chunks.join('');
|
|
@@ -123,7 +137,7 @@ class OutputStreamer {
|
|
|
123
137
|
* Get the accumulated raw output.
|
|
124
138
|
*/
|
|
125
139
|
getAccumulated() {
|
|
126
|
-
return this.chunks.join('');
|
|
140
|
+
return limitLines(this.chunks.join(''));
|
|
127
141
|
}
|
|
128
142
|
}
|
|
129
143
|
/**
|
|
@@ -189,6 +203,13 @@ export class RealExecutor {
|
|
|
189
203
|
child.stderr.on('data', (data) => {
|
|
190
204
|
const text = data.toString();
|
|
191
205
|
stderr.push(text);
|
|
206
|
+
// Collapse when we have too many chunks to prevent memory growth
|
|
207
|
+
if (stderr.length > 16) {
|
|
208
|
+
const accumulated = stderr.join('');
|
|
209
|
+
const limited = limitLines(accumulated);
|
|
210
|
+
stderr.length = 0;
|
|
211
|
+
stderr.push(limited);
|
|
212
|
+
}
|
|
192
213
|
this.outputCallback?.(text, 'stderr');
|
|
193
214
|
});
|
|
194
215
|
child.on('error', (error) => {
|
|
@@ -200,7 +221,7 @@ export class RealExecutor {
|
|
|
200
221
|
description: cmd.description,
|
|
201
222
|
command: cmd.command,
|
|
202
223
|
output: stdoutStreamer.getAccumulated(),
|
|
203
|
-
errors: error.message,
|
|
224
|
+
errors: limitLines(stderr.join('')) || error.message,
|
|
204
225
|
result: ExecutionResult.Error,
|
|
205
226
|
error: error.message,
|
|
206
227
|
};
|
|
@@ -218,7 +239,7 @@ export class RealExecutor {
|
|
|
218
239
|
description: cmd.description,
|
|
219
240
|
command: cmd.command,
|
|
220
241
|
output,
|
|
221
|
-
errors: stderr.join(''),
|
|
242
|
+
errors: limitLines(stderr.join('')),
|
|
222
243
|
result: success ? ExecutionResult.Success : ExecutionResult.Error,
|
|
223
244
|
error: success ? undefined : `Exit code: ${code}`,
|
|
224
245
|
workdir,
|
|
@@ -278,9 +299,8 @@ export async function executeCommands(commands, onProgress) {
|
|
|
278
299
|
: ExecutionStatus.Failed,
|
|
279
300
|
output,
|
|
280
301
|
});
|
|
281
|
-
// Stop
|
|
282
|
-
|
|
283
|
-
if (output.result !== ExecutionResult.Success && isCritical) {
|
|
302
|
+
// Stop on failure
|
|
303
|
+
if (output.result !== ExecutionResult.Success) {
|
|
284
304
|
break;
|
|
285
305
|
}
|
|
286
306
|
}
|
package/dist/services/timing.js
CHANGED
package/dist/skills/execute.md
CHANGED
|
@@ -24,6 +24,12 @@ You will receive:
|
|
|
24
24
|
- Tasks from user-defined skills include params.skill (skill name) and
|
|
25
25
|
parameter values that were substituted into the action
|
|
26
26
|
|
|
27
|
+
**CRITICAL - Command Count Rule**: You MUST generate EXACTLY one command
|
|
28
|
+
per input task, no more, no less. The number of commands in your response
|
|
29
|
+
MUST match the number of tasks you received. Do NOT split a single task
|
|
30
|
+
into multiple commands or generate extra commands beyond what was
|
|
31
|
+
scheduled.
|
|
32
|
+
|
|
27
33
|
## Skill-Based Command Generation
|
|
28
34
|
|
|
29
35
|
**CRITICAL**: The "Available Skills" section in the prompt defines the ONLY
|
|
@@ -133,6 +139,18 @@ Given tasks from this skill:
|
|
|
133
139
|
Do NOT invent different commands - use exactly what the skill specifies,
|
|
134
140
|
with parameter placeholders replaced by actual values.
|
|
135
141
|
|
|
142
|
+
### Handling Skipped Steps
|
|
143
|
+
|
|
144
|
+
**CRITICAL - STEP ORDER PRESERVATION**: When some steps from a skill are
|
|
145
|
+
omitted during scheduling, you MUST maintain alignment with the
|
|
146
|
+
original step positions in both the Steps and Execution sections. Each
|
|
147
|
+
task corresponds to a specific line number in the skill definition, NOT
|
|
148
|
+
to its sequential position in the task list. If you receive tasks for
|
|
149
|
+
steps 1 and 3 (with step 2 skipped), use Execution lines 1 and 3
|
|
150
|
+
(NOT lines 1 and 2). The step numbers in the task actions indicate
|
|
151
|
+
which Execution line to use - always match by original position, never
|
|
152
|
+
by sequential task index.
|
|
153
|
+
|
|
136
154
|
**CRITICAL - VERBATIM EXECUTION**: Run shell commands EXACTLY as written in
|
|
137
155
|
the ### Execution section. Do NOT:
|
|
138
156
|
- Modify the command string in any way
|
|
@@ -174,7 +192,6 @@ Return a structured response with commands to execute:
|
|
|
174
192
|
- **workdir**: Optional working directory for the command (defaults to
|
|
175
193
|
current)
|
|
176
194
|
- **timeout**: Optional timeout in milliseconds (defaults to 30000)
|
|
177
|
-
- **critical**: Whether failure should stop execution (defaults to true)
|
|
178
195
|
|
|
179
196
|
## Command Generation Guidelines
|
|
180
197
|
|
|
@@ -358,14 +375,12 @@ commands:
|
|
|
358
375
|
|
|
359
376
|
For complex multi-step operations:
|
|
360
377
|
|
|
361
|
-
1. **Sequential dependencies**:
|
|
362
|
-
|
|
378
|
+
1. **Sequential dependencies**: Commands execute in order; any failure stops
|
|
379
|
+
the chain
|
|
363
380
|
2. **Long-running processes**: Set appropriate timeouts (build processes
|
|
364
381
|
may need 10+ minutes)
|
|
365
382
|
3. **Working directories**: Use workdir to ensure commands run in the
|
|
366
383
|
right location
|
|
367
|
-
4. **Error handling**: For non-critical cleanup steps, set critical:
|
|
368
|
-
false
|
|
369
384
|
|
|
370
385
|
## Handling Config Placeholders
|
|
371
386
|
|
|
@@ -424,17 +439,28 @@ Example:
|
|
|
424
439
|
|
|
425
440
|
Before returning commands:
|
|
426
441
|
|
|
427
|
-
1. **CRITICAL:
|
|
442
|
+
1. **CRITICAL: Verify command count matches input task count** - you must
|
|
443
|
+
have exactly one command per input task
|
|
444
|
+
2. **CRITICAL: If tasks have params.skill, verify Available Skills
|
|
428
445
|
section exists**
|
|
429
|
-
|
|
446
|
+
3. **CRITICAL: If tasks have params.skill, verify the skill exists in
|
|
430
447
|
Available Skills section**
|
|
431
|
-
|
|
448
|
+
4. **CRITICAL: If tasks have params.skill, verify the skill has both
|
|
432
449
|
Steps and Execution sections**
|
|
433
|
-
|
|
450
|
+
5. **CRITICAL: If any validation fails, return error response with empty
|
|
434
451
|
commands array**
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
9. Validate that critical flags are set appropriately
|
|
452
|
+
6. Verify each command matches its task description
|
|
453
|
+
7. Check that all task params are incorporated
|
|
454
|
+
8. Ensure paths are properly quoted
|
|
455
|
+
9. Confirm timeouts are reasonable for each operation
|
|
440
456
|
10. Review for any safety concerns
|
|
457
|
+
|
|
458
|
+
## Confirmed Schedule
|
|
459
|
+
|
|
460
|
+
CRITICAL: The user message contains the confirmed schedule that the user
|
|
461
|
+
has reviewed and approved. You MUST generate exactly one command per task
|
|
462
|
+
listed in the confirmed schedule. The number of commands in your response
|
|
463
|
+
MUST equal the number of tasks below. DO NOT add extra commands, DO NOT
|
|
464
|
+
skip tasks, and DO NOT split tasks into multiple commands.
|
|
465
|
+
|
|
466
|
+
Your response MUST contain exactly N commands corresponding to these N tasks.
|
|
@@ -34,10 +34,6 @@ export const executeTool = {
|
|
|
34
34
|
type: 'number',
|
|
35
35
|
description: 'Optional timeout in milliseconds. Defaults to 30000 (30 seconds).',
|
|
36
36
|
},
|
|
37
|
-
critical: {
|
|
38
|
-
type: 'boolean',
|
|
39
|
-
description: 'Whether failure should stop execution of subsequent commands. Defaults to true.',
|
|
40
|
-
},
|
|
41
37
|
},
|
|
42
38
|
required: ['description', 'command'],
|
|
43
39
|
},
|
package/dist/types/schemas.js
CHANGED
package/package.json
CHANGED
package/dist/parser.js
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Parses a comma-separated list of tasks from command-line prompt
|
|
3
|
-
* Strips exclamation marks and periods from each task
|
|
4
|
-
*
|
|
5
|
-
* @param prompt - Raw command-line input string
|
|
6
|
-
* @returns Array of parsed task strings
|
|
7
|
-
*/
|
|
8
|
-
export function parseCommands(prompt) {
|
|
9
|
-
return prompt
|
|
10
|
-
.split(',')
|
|
11
|
-
.map((task) => task.trim().replace(/[!.]/g, '').trim())
|
|
12
|
-
.filter((task) => task.length > 0);
|
|
13
|
-
}
|
|
@@ -1,20 +0,0 @@
|
|
|
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
|
-
}
|
package/dist/ui/Confirm.js
DELETED
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useState } from 'react';
|
|
3
|
-
import { Box, Text } from 'ink';
|
|
4
|
-
import { ComponentStatus, } from '../types/components.js';
|
|
5
|
-
import { Colors, getTextColor, Palette } from '../services/colors.js';
|
|
6
|
-
import { useInput } from '../services/keyboard.js';
|
|
7
|
-
import { UserQuery } from './UserQuery.js';
|
|
8
|
-
export const ConfirmView = ({ message, state, status }) => {
|
|
9
|
-
const isActive = status === ComponentStatus.Active;
|
|
10
|
-
const { selectedIndex } = state;
|
|
11
|
-
const options = [
|
|
12
|
-
{ label: 'yes', value: 'yes', color: Palette.BrightGreen },
|
|
13
|
-
{ label: 'no', value: 'no', color: Colors.Status.Error },
|
|
14
|
-
];
|
|
15
|
-
// Timeline rendering (Done status)
|
|
16
|
-
if (status === ComponentStatus.Done) {
|
|
17
|
-
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { marginBottom: 1, marginLeft: 1, children: _jsx(Text, { color: undefined, children: message }) }), _jsxs(UserQuery, { children: ["> ", options[selectedIndex].label] })] }));
|
|
18
|
-
}
|
|
19
|
-
// Active/Pending rendering
|
|
20
|
-
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { marginBottom: 1, marginLeft: 1, children: _jsx(Text, { color: getTextColor(isActive), children: message }) }), _jsxs(Box, { marginLeft: 1, children: [_jsx(Text, { color: Colors.Action.Select, children: ">" }), _jsx(Text, { children: " " }), _jsx(Box, { children: options.map((option, index) => {
|
|
21
|
-
const isSelected = index === selectedIndex;
|
|
22
|
-
return (_jsx(Box, { marginRight: 2, children: _jsx(Text, { color: isSelected ? option.color : undefined, dimColor: !isSelected, children: option.label }) }, option.value));
|
|
23
|
-
}) })] })] }));
|
|
24
|
-
};
|
|
25
|
-
/**
|
|
26
|
-
* Confirm controller: Manages yes/no selection
|
|
27
|
-
*/
|
|
28
|
-
export function Confirm({ message, status, requestHandlers, onConfirmed, onCancelled, }) {
|
|
29
|
-
const isActive = status === ComponentStatus.Active;
|
|
30
|
-
const [selectedIndex, setSelectedIndex] = useState(0); // 0 = Yes, 1 = No
|
|
31
|
-
useInput((input, key) => {
|
|
32
|
-
if (!isActive)
|
|
33
|
-
return;
|
|
34
|
-
if (key.escape) {
|
|
35
|
-
// Escape: highlight "No" and cancel
|
|
36
|
-
const finalState = { selectedIndex: 1, confirmed: false };
|
|
37
|
-
requestHandlers.onCompleted(finalState);
|
|
38
|
-
onCancelled();
|
|
39
|
-
}
|
|
40
|
-
else if (key.tab) {
|
|
41
|
-
// Toggle between Yes (0) and No (1)
|
|
42
|
-
setSelectedIndex((prev) => (prev === 0 ? 1 : 0));
|
|
43
|
-
}
|
|
44
|
-
else if (key.return) {
|
|
45
|
-
// Confirm selection
|
|
46
|
-
const finalState = {
|
|
47
|
-
selectedIndex,
|
|
48
|
-
confirmed: true,
|
|
49
|
-
};
|
|
50
|
-
requestHandlers.onCompleted(finalState);
|
|
51
|
-
if (selectedIndex === 0) {
|
|
52
|
-
onConfirmed();
|
|
53
|
-
}
|
|
54
|
-
else {
|
|
55
|
-
onCancelled();
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
}, { isActive });
|
|
59
|
-
// Controller always renders View, passing current state
|
|
60
|
-
const state = { selectedIndex, confirmed: false };
|
|
61
|
-
return _jsx(ConfirmView, { message: message, state: state, status: status });
|
|
62
|
-
}
|