prompt-language-shell 0.5.2 → 0.6.0
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/config/ANSWER.md +4 -0
- package/dist/config/PLAN.md +23 -0
- package/dist/config/VALIDATE.md +12 -11
- package/dist/services/components.js +54 -64
- package/dist/services/configuration.js +84 -0
- package/dist/services/messages.js +22 -0
- package/dist/services/queue.js +2 -2
- package/dist/services/refinement.js +36 -0
- package/dist/services/task-router.js +135 -0
- package/dist/types/types.js +0 -1
- package/dist/ui/Answer.js +18 -27
- package/dist/ui/Command.js +45 -27
- package/dist/ui/Component.js +23 -50
- package/dist/ui/Config.js +49 -24
- package/dist/ui/Confirm.js +17 -11
- package/dist/ui/Execute.js +66 -45
- package/dist/ui/Feedback.js +1 -1
- package/dist/ui/Introspect.js +26 -23
- package/dist/ui/Main.js +71 -100
- package/dist/ui/Message.js +1 -1
- package/dist/ui/Plan.js +54 -32
- package/dist/ui/Refinement.js +6 -7
- package/dist/ui/Report.js +1 -1
- package/dist/ui/UserQuery.js +6 -0
- package/dist/ui/Validate.js +49 -19
- package/dist/ui/Welcome.js +1 -1
- package/dist/ui/Workflow.js +119 -0
- package/package.json +1 -1
- package/dist/handlers/answer.js +0 -21
- package/dist/handlers/command.js +0 -34
- package/dist/handlers/config.js +0 -88
- package/dist/handlers/execute.js +0 -46
- package/dist/handlers/execution.js +0 -140
- package/dist/handlers/introspect.js +0 -21
- package/dist/handlers/plan.js +0 -79
- package/dist/types/handlers.js +0 -1
- package/dist/ui/AnswerDisplay.js +0 -8
- package/dist/ui/Column.js +0 -7
package/dist/config/ANSWER.md
CHANGED
|
@@ -42,6 +42,8 @@ Provide a direct, helpful answer following these strict formatting rules:
|
|
|
42
42
|
- Break long sentences naturally at phrase boundaries
|
|
43
43
|
- If the answer requires more than 4 lines, prioritize the most essential
|
|
44
44
|
information
|
|
45
|
+
- **Do NOT use citation tags** like `<cite>` or any HTML/XML markup
|
|
46
|
+
- Provide direct answers in plain text only
|
|
45
47
|
|
|
46
48
|
## Examples
|
|
47
49
|
|
|
@@ -112,8 +114,10 @@ They enable cleaner, more reusable component logic.
|
|
|
112
114
|
❌ Including unnecessary details
|
|
113
115
|
❌ Using overly technical jargon without explanation
|
|
114
116
|
❌ Repeating the question in the answer
|
|
117
|
+
❌ Using citation tags like `<cite>` or any HTML/XML markup
|
|
115
118
|
|
|
116
119
|
✅ Direct, concise answers
|
|
117
120
|
✅ Proper line breaks at natural phrase boundaries
|
|
118
121
|
✅ Essential information only
|
|
119
122
|
✅ Clear, accessible language
|
|
123
|
+
✅ Plain text only - no markup tags
|
package/dist/config/PLAN.md
CHANGED
|
@@ -280,6 +280,29 @@ Examples that should be aborted as offensive:
|
|
|
280
280
|
- Requests to create malware or exploit vulnerabilities
|
|
281
281
|
- Requests with offensive, discriminatory, or abusive language
|
|
282
282
|
|
|
283
|
+
**CRITICAL: Distinguishing Questions from Actions**
|
|
284
|
+
|
|
285
|
+
User requests fall into two categories:
|
|
286
|
+
|
|
287
|
+
1. **Information requests (questions)** - Must use question keywords:
|
|
288
|
+
- "explain", "answer", "describe", "tell me", "say", "what is", "what are",
|
|
289
|
+
"how does", "how do", "find", "search", "lookup"
|
|
290
|
+
- Example: "pls explain TypeScript" → answer type
|
|
291
|
+
- Example: "pls what is the weather" → answer type
|
|
292
|
+
|
|
293
|
+
2. **Action requests (commands)** - Must match available skills:
|
|
294
|
+
- Verbs like "test", "deploy", "process", "backup", "sync"
|
|
295
|
+
- If verb matches a skill → use that skill
|
|
296
|
+
- If verb does NOT match any skill → use "ignore" type
|
|
297
|
+
- Example: "pls test" with no test skill → ignore type
|
|
298
|
+
- Example: "pls reverberate" with no reverberate skill → ignore type
|
|
299
|
+
- Example: "pls shut down" with no shutdown skill → ignore type
|
|
300
|
+
|
|
301
|
+
**Critical rule:** Requests using action verbs that don't match question
|
|
302
|
+
keywords AND don't match any available skills should ALWAYS be classified
|
|
303
|
+
as "ignore" type. Do NOT try to infer or create generic execute tasks for
|
|
304
|
+
unrecognized verbs.
|
|
305
|
+
|
|
283
306
|
**For requests with clear intent:**
|
|
284
307
|
|
|
285
308
|
1. **Introspection requests** - Use "introspect" type when request asks about
|
package/dist/config/VALIDATE.md
CHANGED
|
@@ -29,12 +29,12 @@ For each CONFIG task, create a natural language description that:
|
|
|
29
29
|
|
|
30
30
|
## Description Format
|
|
31
31
|
|
|
32
|
-
**Format:** "Brief description" (
|
|
32
|
+
**Format:** "Brief description" (DO NOT include {config.path}!)
|
|
33
33
|
|
|
34
34
|
The description should:
|
|
35
35
|
- Start with what the config value represents (e.g., "Path to...", "URL for...", "Name of...")
|
|
36
36
|
- Be SHORT and direct - no extra details or variant explanations
|
|
37
|
-
-
|
|
37
|
+
- NEVER include the config path in curly brackets like {config.path}
|
|
38
38
|
|
|
39
39
|
## Examples
|
|
40
40
|
|
|
@@ -50,7 +50,7 @@ The description should:
|
|
|
50
50
|
message: ""
|
|
51
51
|
tasks: [
|
|
52
52
|
{
|
|
53
|
-
action: "Path to Alpha repository
|
|
53
|
+
action: "Path to Alpha repository",
|
|
54
54
|
type: "config",
|
|
55
55
|
params: { key: "project.alpha.repo" }
|
|
56
56
|
}
|
|
@@ -69,7 +69,7 @@ tasks: [
|
|
|
69
69
|
message: ""
|
|
70
70
|
tasks: [
|
|
71
71
|
{
|
|
72
|
-
action: "Staging environment URL
|
|
72
|
+
action: "Staging environment URL",
|
|
73
73
|
type: "config",
|
|
74
74
|
params: { key: "env.staging.url" }
|
|
75
75
|
}
|
|
@@ -88,7 +88,7 @@ tasks: [
|
|
|
88
88
|
message: ""
|
|
89
89
|
tasks: [
|
|
90
90
|
{
|
|
91
|
-
action: "Path to Beta workspace
|
|
91
|
+
action: "Path to Beta workspace",
|
|
92
92
|
type: "config",
|
|
93
93
|
params: { key: "workspace.beta.path" }
|
|
94
94
|
}
|
|
@@ -98,10 +98,10 @@ tasks: [
|
|
|
98
98
|
## Guidelines
|
|
99
99
|
|
|
100
100
|
1. **Use skill context**: Read the skill's Description section to understand what the variant represents
|
|
101
|
-
2. **Be specific**: Don't just say "Repository path" - say "Alpha
|
|
102
|
-
3. **Add helpful details**: Include information from the description
|
|
103
|
-
4. **Keep it concise**: One
|
|
104
|
-
5. **
|
|
101
|
+
2. **Be specific**: Don't just say "Repository path" - say "Path to Alpha repository"
|
|
102
|
+
3. **Add helpful details**: Include information from the description when relevant
|
|
103
|
+
4. **Keep it concise**: One brief phrase that clearly explains what's needed
|
|
104
|
+
5. **Never include the path**: Do not append `{config.path}` - it's shown separately in debug mode
|
|
105
105
|
|
|
106
106
|
## Common Config Types
|
|
107
107
|
|
|
@@ -122,7 +122,7 @@ Return a message field (can be empty string) and an array of CONFIG tasks:
|
|
|
122
122
|
message: ""
|
|
123
123
|
tasks: [
|
|
124
124
|
{
|
|
125
|
-
action: "Natural description
|
|
125
|
+
action: "Natural description without config path",
|
|
126
126
|
type: "config",
|
|
127
127
|
params: { key: "config.path" }
|
|
128
128
|
},
|
|
@@ -136,4 +136,5 @@ tasks: [
|
|
|
136
136
|
- All tasks must include params.key with the config path
|
|
137
137
|
- Descriptions should be helpful and contextual, not just technical
|
|
138
138
|
- Use information from Available Skills section to provide context
|
|
139
|
-
- Keep descriptions to one
|
|
139
|
+
- Keep descriptions to one brief phrase (3-6 words)
|
|
140
|
+
- NEVER include the config path in the action/description - it's shown separately
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
2
3
|
import { ComponentName } from '../types/types.js';
|
|
3
|
-
import {
|
|
4
|
+
import { parse as parseYaml } from 'yaml';
|
|
5
|
+
import { getConfigPath, getConfigSchema, loadConfig, } from './configuration.js';
|
|
4
6
|
import { getConfirmationMessage } from './messages.js';
|
|
5
7
|
import { StepType } from '../ui/Config.js';
|
|
6
|
-
export function markAsDone(component) {
|
|
7
|
-
return { ...component, state: { ...component.state, done: true } };
|
|
8
|
-
}
|
|
9
8
|
export function createWelcomeDefinition(app) {
|
|
10
9
|
return {
|
|
11
10
|
id: randomUUID(),
|
|
@@ -58,27 +57,43 @@ function getValidator(definition) {
|
|
|
58
57
|
export function createConfigStepsFromSchema(keys) {
|
|
59
58
|
const schema = getConfigSchema();
|
|
60
59
|
let currentConfig = null;
|
|
60
|
+
let rawConfig = null;
|
|
61
|
+
// Load validated config (may fail if config has validation errors)
|
|
61
62
|
try {
|
|
62
63
|
currentConfig = loadConfig();
|
|
63
64
|
}
|
|
64
65
|
catch {
|
|
65
|
-
// Config doesn't exist
|
|
66
|
+
// Config doesn't exist or has validation errors, use defaults
|
|
67
|
+
}
|
|
68
|
+
// Load raw config separately (for discovered keys not in schema)
|
|
69
|
+
try {
|
|
70
|
+
const configFile = getConfigPath();
|
|
71
|
+
if (existsSync(configFile)) {
|
|
72
|
+
const content = readFileSync(configFile, 'utf-8');
|
|
73
|
+
rawConfig = parseYaml(content);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
// Config file doesn't exist or can't be parsed
|
|
66
78
|
}
|
|
67
79
|
return keys.map((key) => {
|
|
68
80
|
// Check if key is in schema (built-in config)
|
|
69
81
|
if (!(key in schema)) {
|
|
70
|
-
// Key is not in schema - it's from a skill
|
|
71
|
-
// Create a simple text step with
|
|
82
|
+
// Key is not in schema - it's from a skill or discovered config
|
|
83
|
+
// Create a simple text step with the full path as description
|
|
72
84
|
const keyParts = key.split('.');
|
|
73
85
|
const shortKey = keyParts[keyParts.length - 1];
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
86
|
+
// Load current value if it exists (use rawConfig since discovered keys aren't in validated config)
|
|
87
|
+
const currentValue = getConfigValue(rawConfig, key);
|
|
88
|
+
const value = currentValue !== undefined && typeof currentValue === 'string'
|
|
89
|
+
? currentValue
|
|
90
|
+
: null;
|
|
77
91
|
return {
|
|
78
|
-
description:
|
|
92
|
+
description: key,
|
|
79
93
|
key: shortKey,
|
|
94
|
+
path: key,
|
|
80
95
|
type: StepType.Text,
|
|
81
|
-
value
|
|
96
|
+
value,
|
|
82
97
|
validate: () => true, // Accept any string for now
|
|
83
98
|
};
|
|
84
99
|
}
|
|
@@ -98,6 +113,7 @@ export function createConfigStepsFromSchema(keys) {
|
|
|
98
113
|
return {
|
|
99
114
|
description: definition.description,
|
|
100
115
|
key: shortKey,
|
|
116
|
+
path: key,
|
|
101
117
|
type: StepType.Text,
|
|
102
118
|
value,
|
|
103
119
|
validate: getValidator(definition),
|
|
@@ -112,6 +128,7 @@ export function createConfigStepsFromSchema(keys) {
|
|
|
112
128
|
return {
|
|
113
129
|
description: definition.description,
|
|
114
130
|
key: shortKey,
|
|
131
|
+
path: key,
|
|
115
132
|
type: StepType.Text,
|
|
116
133
|
value,
|
|
117
134
|
validate: getValidator(definition),
|
|
@@ -127,6 +144,7 @@ export function createConfigStepsFromSchema(keys) {
|
|
|
127
144
|
return {
|
|
128
145
|
description: definition.description,
|
|
129
146
|
key: shortKey,
|
|
147
|
+
path: key,
|
|
130
148
|
type: StepType.Selection,
|
|
131
149
|
options: definition.values.map((value) => ({
|
|
132
150
|
label: value,
|
|
@@ -143,6 +161,7 @@ export function createConfigStepsFromSchema(keys) {
|
|
|
143
161
|
return {
|
|
144
162
|
description: definition.description,
|
|
145
163
|
key: shortKey,
|
|
164
|
+
path: key,
|
|
146
165
|
type: StepType.Selection,
|
|
147
166
|
options: [
|
|
148
167
|
{ label: 'Yes', value: 'true' },
|
|
@@ -159,7 +178,7 @@ export function createConfigDefinition(onFinished, onAborted) {
|
|
|
159
178
|
return {
|
|
160
179
|
id: randomUUID(),
|
|
161
180
|
name: ComponentName.Config,
|
|
162
|
-
state: {
|
|
181
|
+
state: {},
|
|
163
182
|
props: {
|
|
164
183
|
steps: createConfigSteps(),
|
|
165
184
|
onFinished,
|
|
@@ -174,7 +193,7 @@ export function createConfigDefinitionWithKeys(keys, onFinished, onAborted) {
|
|
|
174
193
|
return {
|
|
175
194
|
id: randomUUID(),
|
|
176
195
|
name: ComponentName.Config,
|
|
177
|
-
state: {
|
|
196
|
+
state: {},
|
|
178
197
|
props: {
|
|
179
198
|
steps: createConfigStepsFromSchema(keys),
|
|
180
199
|
onFinished,
|
|
@@ -182,29 +201,22 @@ export function createConfigDefinitionWithKeys(keys, onFinished, onAborted) {
|
|
|
182
201
|
},
|
|
183
202
|
};
|
|
184
203
|
}
|
|
185
|
-
export function createCommandDefinition(command, service
|
|
204
|
+
export function createCommandDefinition(command, service) {
|
|
186
205
|
return {
|
|
187
206
|
id: randomUUID(),
|
|
188
207
|
name: ComponentName.Command,
|
|
189
|
-
state: {
|
|
190
|
-
done: false,
|
|
191
|
-
isLoading: true,
|
|
192
|
-
},
|
|
208
|
+
state: {},
|
|
193
209
|
props: {
|
|
194
210
|
command,
|
|
195
211
|
service,
|
|
196
|
-
onError,
|
|
197
|
-
onComplete,
|
|
198
|
-
onAborted,
|
|
199
212
|
},
|
|
200
213
|
};
|
|
201
214
|
}
|
|
202
|
-
export function createPlanDefinition(message, tasks,
|
|
215
|
+
export function createPlanDefinition(message, tasks, onSelectionConfirmed) {
|
|
203
216
|
return {
|
|
204
217
|
id: randomUUID(),
|
|
205
218
|
name: ComponentName.Plan,
|
|
206
219
|
state: {
|
|
207
|
-
done: false,
|
|
208
220
|
highlightedIndex: null,
|
|
209
221
|
currentDefineGroupIndex: 0,
|
|
210
222
|
completedSelections: [],
|
|
@@ -213,7 +225,6 @@ export function createPlanDefinition(message, tasks, onAborted, onSelectionConfi
|
|
|
213
225
|
message,
|
|
214
226
|
tasks,
|
|
215
227
|
onSelectionConfirmed,
|
|
216
|
-
onAborted,
|
|
217
228
|
},
|
|
218
229
|
};
|
|
219
230
|
}
|
|
@@ -240,7 +251,7 @@ export function createRefinement(text, onAborted) {
|
|
|
240
251
|
return {
|
|
241
252
|
id: randomUUID(),
|
|
242
253
|
name: ComponentName.Refinement,
|
|
243
|
-
state: {
|
|
254
|
+
state: {},
|
|
244
255
|
props: {
|
|
245
256
|
text,
|
|
246
257
|
onAborted,
|
|
@@ -251,7 +262,7 @@ export function createConfirmDefinition(onConfirmed, onCancelled) {
|
|
|
251
262
|
return {
|
|
252
263
|
id: randomUUID(),
|
|
253
264
|
name: ComponentName.Confirm,
|
|
254
|
-
state: {
|
|
265
|
+
state: {},
|
|
255
266
|
props: {
|
|
256
267
|
message: getConfirmationMessage(),
|
|
257
268
|
onConfirmed,
|
|
@@ -259,20 +270,14 @@ export function createConfirmDefinition(onConfirmed, onCancelled) {
|
|
|
259
270
|
},
|
|
260
271
|
};
|
|
261
272
|
}
|
|
262
|
-
export function createIntrospectDefinition(tasks, service
|
|
273
|
+
export function createIntrospectDefinition(tasks, service) {
|
|
263
274
|
return {
|
|
264
275
|
id: randomUUID(),
|
|
265
276
|
name: ComponentName.Introspect,
|
|
266
|
-
state: {
|
|
267
|
-
done: false,
|
|
268
|
-
isLoading: true,
|
|
269
|
-
},
|
|
277
|
+
state: {},
|
|
270
278
|
props: {
|
|
271
279
|
tasks,
|
|
272
280
|
service,
|
|
273
|
-
onError,
|
|
274
|
-
onComplete,
|
|
275
|
-
onAborted,
|
|
276
281
|
},
|
|
277
282
|
};
|
|
278
283
|
}
|
|
@@ -286,49 +291,37 @@ export function createReportDefinition(message, capabilities) {
|
|
|
286
291
|
},
|
|
287
292
|
};
|
|
288
293
|
}
|
|
289
|
-
export function createAnswerDefinition(question, service
|
|
294
|
+
export function createAnswerDefinition(question, service) {
|
|
290
295
|
return {
|
|
291
296
|
id: randomUUID(),
|
|
292
297
|
name: ComponentName.Answer,
|
|
293
|
-
state: {
|
|
294
|
-
done: false,
|
|
295
|
-
isLoading: true,
|
|
296
|
-
},
|
|
298
|
+
state: {},
|
|
297
299
|
props: {
|
|
298
300
|
question,
|
|
299
301
|
service,
|
|
300
|
-
onError,
|
|
301
|
-
onComplete,
|
|
302
|
-
onAborted,
|
|
303
|
-
},
|
|
304
|
-
};
|
|
305
|
-
}
|
|
306
|
-
export function createAnswerDisplayDefinition(answer) {
|
|
307
|
-
return {
|
|
308
|
-
id: randomUUID(),
|
|
309
|
-
name: ComponentName.AnswerDisplay,
|
|
310
|
-
props: {
|
|
311
|
-
answer,
|
|
312
302
|
},
|
|
313
303
|
};
|
|
314
304
|
}
|
|
315
305
|
export function isStateless(component) {
|
|
316
306
|
return !('state' in component);
|
|
317
307
|
}
|
|
318
|
-
|
|
308
|
+
/**
|
|
309
|
+
* Mark a component as done. Returns the component to be added to timeline.
|
|
310
|
+
* Components use handlers.updateState to save their state before completion,
|
|
311
|
+
* so this function simply returns the component as-is.
|
|
312
|
+
*/
|
|
313
|
+
export function markAsDone(component) {
|
|
314
|
+
// State already updated via handlers.updateState
|
|
315
|
+
return component;
|
|
316
|
+
}
|
|
317
|
+
export function createExecuteDefinition(tasks, service) {
|
|
319
318
|
return {
|
|
320
319
|
id: randomUUID(),
|
|
321
320
|
name: ComponentName.Execute,
|
|
322
|
-
state: {
|
|
323
|
-
done: false,
|
|
324
|
-
isLoading: true,
|
|
325
|
-
},
|
|
321
|
+
state: {},
|
|
326
322
|
props: {
|
|
327
323
|
tasks,
|
|
328
324
|
service,
|
|
329
|
-
onError,
|
|
330
|
-
onComplete,
|
|
331
|
-
onAborted,
|
|
332
325
|
},
|
|
333
326
|
};
|
|
334
327
|
}
|
|
@@ -336,10 +329,7 @@ export function createValidateDefinition(missingConfig, userRequest, service, on
|
|
|
336
329
|
return {
|
|
337
330
|
id: randomUUID(),
|
|
338
331
|
name: ComponentName.Validate,
|
|
339
|
-
state: {
|
|
340
|
-
done: false,
|
|
341
|
-
isLoading: true,
|
|
342
|
-
},
|
|
332
|
+
state: {},
|
|
343
333
|
props: {
|
|
344
334
|
missingConfig,
|
|
345
335
|
userRequest,
|
|
@@ -123,6 +123,7 @@ export function saveConfig(section, config) {
|
|
|
123
123
|
}
|
|
124
124
|
export function saveAnthropicConfig(config) {
|
|
125
125
|
saveConfig('anthropic', config);
|
|
126
|
+
return loadConfig();
|
|
126
127
|
}
|
|
127
128
|
export function saveDebugSetting(debug) {
|
|
128
129
|
saveConfig('settings', { debug });
|
|
@@ -200,6 +201,67 @@ export function getConfigSchema() {
|
|
|
200
201
|
// Future: ...loadSkillSchemas()
|
|
201
202
|
};
|
|
202
203
|
}
|
|
204
|
+
/**
|
|
205
|
+
* Get missing required configuration keys
|
|
206
|
+
* Returns array of keys that are required but not present or invalid in config
|
|
207
|
+
*/
|
|
208
|
+
export function getMissingConfigKeys() {
|
|
209
|
+
const schema = getConfigSchema();
|
|
210
|
+
const missing = [];
|
|
211
|
+
let currentConfig = null;
|
|
212
|
+
try {
|
|
213
|
+
currentConfig = loadConfig();
|
|
214
|
+
}
|
|
215
|
+
catch {
|
|
216
|
+
// Config doesn't exist
|
|
217
|
+
}
|
|
218
|
+
for (const [key, definition] of Object.entries(schema)) {
|
|
219
|
+
if (!definition.required) {
|
|
220
|
+
continue;
|
|
221
|
+
}
|
|
222
|
+
// Get current value for this key
|
|
223
|
+
const parts = key.split('.');
|
|
224
|
+
let value = currentConfig;
|
|
225
|
+
for (const part of parts) {
|
|
226
|
+
if (value && typeof value === 'object' && part in value) {
|
|
227
|
+
value = value[part];
|
|
228
|
+
}
|
|
229
|
+
else {
|
|
230
|
+
value = undefined;
|
|
231
|
+
break;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
// Check if value is missing or invalid
|
|
235
|
+
if (value === undefined || value === null) {
|
|
236
|
+
missing.push(key);
|
|
237
|
+
continue;
|
|
238
|
+
}
|
|
239
|
+
// Validate based on type
|
|
240
|
+
let isValid = false;
|
|
241
|
+
switch (definition.type) {
|
|
242
|
+
case 'regexp':
|
|
243
|
+
isValid = typeof value === 'string' && definition.pattern.test(value);
|
|
244
|
+
break;
|
|
245
|
+
case 'string':
|
|
246
|
+
isValid = typeof value === 'string';
|
|
247
|
+
break;
|
|
248
|
+
case 'enum':
|
|
249
|
+
isValid =
|
|
250
|
+
typeof value === 'string' && definition.values.includes(value);
|
|
251
|
+
break;
|
|
252
|
+
case 'number':
|
|
253
|
+
isValid = typeof value === 'number';
|
|
254
|
+
break;
|
|
255
|
+
case 'boolean':
|
|
256
|
+
isValid = typeof value === 'boolean';
|
|
257
|
+
break;
|
|
258
|
+
}
|
|
259
|
+
if (!isValid) {
|
|
260
|
+
missing.push(key);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
return missing;
|
|
264
|
+
}
|
|
203
265
|
/**
|
|
204
266
|
* Get available config structure for CONFIG tool
|
|
205
267
|
* Returns keys with descriptions only (no values for privacy)
|
|
@@ -246,3 +308,25 @@ export function getAvailableConfigStructure() {
|
|
|
246
308
|
}
|
|
247
309
|
return structure;
|
|
248
310
|
}
|
|
311
|
+
/**
|
|
312
|
+
* Unflatten dotted keys into nested structure
|
|
313
|
+
* Example: { "product.alpha.path": "value" } -> { product: { alpha: { path: "value" } } }
|
|
314
|
+
*/
|
|
315
|
+
export function unflattenConfig(dotted) {
|
|
316
|
+
const result = {};
|
|
317
|
+
for (const [dottedKey, value] of Object.entries(dotted)) {
|
|
318
|
+
const parts = dottedKey.split('.');
|
|
319
|
+
const section = parts[0];
|
|
320
|
+
// Initialize section if needed
|
|
321
|
+
result[section] = result[section] ?? {};
|
|
322
|
+
// Build nested structure for this section
|
|
323
|
+
let current = result[section];
|
|
324
|
+
for (let i = 1; i < parts.length - 1; i++) {
|
|
325
|
+
current[parts[i]] = current[parts[i]] ?? {};
|
|
326
|
+
current = current[parts[i]];
|
|
327
|
+
}
|
|
328
|
+
// Set final value
|
|
329
|
+
current[parts[parts.length - 1]] = value;
|
|
330
|
+
}
|
|
331
|
+
return result;
|
|
332
|
+
}
|
|
@@ -43,6 +43,28 @@ export function getCancellationMessage(operation) {
|
|
|
43
43
|
];
|
|
44
44
|
return templates[Math.floor(Math.random() * templates.length)];
|
|
45
45
|
}
|
|
46
|
+
/**
|
|
47
|
+
* Returns an error message when the request cannot be understood.
|
|
48
|
+
* Randomly selects from variations to sound natural.
|
|
49
|
+
*/
|
|
50
|
+
export function getUnknownRequestMessage() {
|
|
51
|
+
const messages = [
|
|
52
|
+
'I do not understand the request.',
|
|
53
|
+
'I cannot understand what you want me to do.',
|
|
54
|
+
"I'm not sure what you're asking for.",
|
|
55
|
+
'I cannot determine what action to take.',
|
|
56
|
+
'This request is unclear to me.',
|
|
57
|
+
'I do not recognize this command.',
|
|
58
|
+
];
|
|
59
|
+
return messages[Math.floor(Math.random() * messages.length)];
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Returns an error message for mixed task types.
|
|
63
|
+
*/
|
|
64
|
+
export function getMixedTaskTypesError(types) {
|
|
65
|
+
const typeList = types.join(', ');
|
|
66
|
+
return `Mixed task types are not supported. Found: ${typeList}. All tasks in a plan must have the same type.`;
|
|
67
|
+
}
|
|
46
68
|
/**
|
|
47
69
|
* Feedback messages for various operations
|
|
48
70
|
*/
|
package/dist/services/queue.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { FeedbackType } from '../types/types.js';
|
|
2
|
-
import { createFeedback
|
|
2
|
+
import { createFeedback } from './components.js';
|
|
3
3
|
import { FeedbackMessages } from './messages.js';
|
|
4
4
|
import { exitApp } from './process.js';
|
|
5
5
|
/**
|
|
@@ -37,7 +37,7 @@ export function withQueueHandler(componentName, callback, shouldExit = false, ex
|
|
|
37
37
|
*/
|
|
38
38
|
export function createErrorHandler(componentName, addToTimeline) {
|
|
39
39
|
return (error) => withQueueHandler(componentName, (first) => {
|
|
40
|
-
addToTimeline(
|
|
40
|
+
addToTimeline(first, createFeedback(FeedbackType.Failed, FeedbackMessages.UnexpectedError, error));
|
|
41
41
|
return undefined;
|
|
42
42
|
}, true, 1);
|
|
43
43
|
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { createRefinement } from './components.js';
|
|
2
|
+
import { formatErrorMessage, getRefiningMessage } from './messages.js';
|
|
3
|
+
import { routeTasksWithConfirm } from './task-router.js';
|
|
4
|
+
/**
|
|
5
|
+
* Handle refinement flow for DEFINE tasks
|
|
6
|
+
* Called when user selects options from a plan with DEFINE tasks
|
|
7
|
+
*/
|
|
8
|
+
export async function handleRefinement(selectedTasks, service, originalCommand, handlers) {
|
|
9
|
+
// Create and add refinement component to queue
|
|
10
|
+
const refinementDef = createRefinement(getRefiningMessage(), (operation) => {
|
|
11
|
+
handlers.onAborted(operation);
|
|
12
|
+
});
|
|
13
|
+
handlers.addToQueue(refinementDef);
|
|
14
|
+
try {
|
|
15
|
+
// Build refined command from selected tasks
|
|
16
|
+
const refinedCommand = selectedTasks
|
|
17
|
+
.map((task) => {
|
|
18
|
+
const action = task.action.toLowerCase().replace(/,/g, ' -');
|
|
19
|
+
const type = task.type;
|
|
20
|
+
return `${action} (type: ${type})`;
|
|
21
|
+
})
|
|
22
|
+
.join(', ');
|
|
23
|
+
// Call LLM to refine plan with selected tasks
|
|
24
|
+
const refinedResult = await service.processWithTool(refinedCommand, 'plan');
|
|
25
|
+
// Complete the Refinement component
|
|
26
|
+
handlers.completeActive();
|
|
27
|
+
// Route refined tasks to appropriate components
|
|
28
|
+
routeTasksWithConfirm(refinedResult.tasks, refinedResult.message, service, originalCommand, handlers, false // No DEFINE tasks in refined result
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
catch (err) {
|
|
32
|
+
handlers.completeActive();
|
|
33
|
+
const errorMessage = formatErrorMessage(err);
|
|
34
|
+
handlers.onError(errorMessage);
|
|
35
|
+
}
|
|
36
|
+
}
|