prompt-language-shell 0.7.8 → 0.8.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/services/anthropic.js +29 -3
- package/dist/services/colors.js +35 -9
- package/dist/services/components.js +28 -7
- package/dist/services/config-labels.js +75 -0
- package/dist/services/config-utils.js +20 -0
- package/dist/services/configuration.js +15 -36
- package/dist/services/registry.js +1 -1
- package/dist/services/router.js +6 -6
- package/dist/services/shell.js +1 -0
- package/dist/services/skills.js +3 -3
- package/dist/skills/introspect.md +52 -43
- package/dist/skills/schedule.md +8 -3
- package/dist/tools/introspect.tool.js +18 -9
- package/dist/types/guards.js +25 -0
- package/dist/types/types.js +6 -0
- package/dist/ui/Answer.js +7 -7
- package/dist/ui/Command.js +12 -11
- package/dist/ui/Component.js +2 -2
- package/dist/ui/Config.js +66 -26
- package/dist/ui/Confirm.js +6 -6
- package/dist/ui/Execute.js +124 -36
- package/dist/ui/Feedback.js +1 -1
- package/dist/ui/Introspect.js +5 -52
- package/dist/ui/Label.js +1 -1
- package/dist/ui/List.js +2 -1
- package/dist/ui/Main.js +1 -1
- package/dist/ui/Report.js +4 -8
- package/dist/ui/Schedule.js +5 -5
- package/dist/ui/Spinner.js +5 -2
- package/dist/ui/Subtask.js +14 -3
- package/dist/ui/Task.js +19 -14
- package/dist/ui/Validate.js +42 -31
- package/dist/ui/Workflow.js +1 -1
- package/package.json +12 -12
|
@@ -48,8 +48,8 @@ export function cleanAnswerText(text) {
|
|
|
48
48
|
export class AnthropicService {
|
|
49
49
|
client;
|
|
50
50
|
model;
|
|
51
|
-
constructor(key, model = 'claude-haiku-4-5
|
|
52
|
-
this.client = new Anthropic({ apiKey: key });
|
|
51
|
+
constructor(key, model = 'claude-haiku-4-5', timeout = 30000) {
|
|
52
|
+
this.client = new Anthropic({ apiKey: key, timeout });
|
|
53
53
|
this.model = model;
|
|
54
54
|
}
|
|
55
55
|
async processWithTool(command, toolName, customInstructions) {
|
|
@@ -186,7 +186,33 @@ export class AnthropicService {
|
|
|
186
186
|
debug,
|
|
187
187
|
};
|
|
188
188
|
}
|
|
189
|
-
// Handle
|
|
189
|
+
// Handle introspect tool response
|
|
190
|
+
if (toolName === 'introspect') {
|
|
191
|
+
if (!input.message || typeof input.message !== 'string') {
|
|
192
|
+
throw new Error('Invalid tool response: missing or invalid message field');
|
|
193
|
+
}
|
|
194
|
+
if (!input.capabilities || !Array.isArray(input.capabilities)) {
|
|
195
|
+
throw new Error('Invalid tool response: missing or invalid capabilities array');
|
|
196
|
+
}
|
|
197
|
+
// Validate each capability has required fields
|
|
198
|
+
input.capabilities.forEach((cap, i) => {
|
|
199
|
+
if (!cap.name || typeof cap.name !== 'string') {
|
|
200
|
+
throw new Error(`Invalid capability at index ${String(i)}: missing or invalid 'name' field`);
|
|
201
|
+
}
|
|
202
|
+
if (!cap.description || typeof cap.description !== 'string') {
|
|
203
|
+
throw new Error(`Invalid capability at index ${String(i)}: missing or invalid 'description' field`);
|
|
204
|
+
}
|
|
205
|
+
if (typeof cap.origin !== 'string') {
|
|
206
|
+
throw new Error(`Invalid capability at index ${String(i)}: invalid 'origin' field`);
|
|
207
|
+
}
|
|
208
|
+
});
|
|
209
|
+
return {
|
|
210
|
+
message: input.message,
|
|
211
|
+
capabilities: input.capabilities,
|
|
212
|
+
debug,
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
// Handle schedule tool responses
|
|
190
216
|
if (input.message === undefined || typeof input.message !== 'string') {
|
|
191
217
|
throw new Error('Invalid tool response: missing or invalid message field');
|
|
192
218
|
}
|
package/dist/services/colors.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { FeedbackType, TaskType } from '../types/types.js';
|
|
1
|
+
import { FeedbackType, Origin, TaskType } from '../types/types.js';
|
|
2
2
|
import { DebugLevel } from './configuration.js';
|
|
3
3
|
import { ExecutionStatus } from './shell.js';
|
|
4
4
|
/**
|
|
@@ -8,7 +8,6 @@ import { ExecutionStatus } from './shell.js';
|
|
|
8
8
|
export const Palette = {
|
|
9
9
|
White: '#ffffff',
|
|
10
10
|
AshGray: '#d0d0d0',
|
|
11
|
-
PaleGreen: '#a8dcbc',
|
|
12
11
|
Gray: '#888888',
|
|
13
12
|
DarkGray: '#666666',
|
|
14
13
|
CharcoalGray: '#282828',
|
|
@@ -16,8 +15,8 @@ export const Palette = {
|
|
|
16
15
|
LightGreen: '#65b595',
|
|
17
16
|
BrightGreen: '#3e9a3e',
|
|
18
17
|
Yellow: '#cccc5c',
|
|
19
|
-
LightYellow: '#d4d47a',
|
|
20
18
|
Orange: '#f48c80',
|
|
19
|
+
MediumOrange: '#d07560',
|
|
21
20
|
DarkOrange: '#ab5e40',
|
|
22
21
|
BurntOrange: '#cc7a5c',
|
|
23
22
|
Red: '#cc5c5c',
|
|
@@ -47,7 +46,7 @@ export const Colors = {
|
|
|
47
46
|
Status: {
|
|
48
47
|
Success: Palette.BrightGreen,
|
|
49
48
|
Error: Palette.Red,
|
|
50
|
-
Warning: Palette.
|
|
49
|
+
Warning: Palette.MediumOrange,
|
|
51
50
|
Info: Palette.Cyan,
|
|
52
51
|
},
|
|
53
52
|
Label: {
|
|
@@ -130,9 +129,17 @@ const taskColors = {
|
|
|
130
129
|
const feedbackColors = {
|
|
131
130
|
[FeedbackType.Info]: Colors.Status.Info,
|
|
132
131
|
[FeedbackType.Succeeded]: Colors.Status.Success,
|
|
133
|
-
[FeedbackType.Aborted]:
|
|
132
|
+
[FeedbackType.Aborted]: Palette.MediumOrange,
|
|
134
133
|
[FeedbackType.Failed]: Colors.Status.Error,
|
|
135
134
|
};
|
|
135
|
+
/**
|
|
136
|
+
* Origin-specific color mappings (internal)
|
|
137
|
+
*/
|
|
138
|
+
const originColors = {
|
|
139
|
+
[Origin.BuiltIn]: Colors.Origin.BuiltIn,
|
|
140
|
+
[Origin.UserProvided]: Colors.Origin.UserProvided,
|
|
141
|
+
[Origin.Indirect]: Colors.Origin.Indirect,
|
|
142
|
+
};
|
|
136
143
|
/**
|
|
137
144
|
* Process null color values based on current/historical state.
|
|
138
145
|
*
|
|
@@ -171,6 +178,17 @@ export function getTaskColors(type, isCurrent) {
|
|
|
171
178
|
export function getFeedbackColor(type, isCurrent) {
|
|
172
179
|
return processColor(feedbackColors[type], isCurrent);
|
|
173
180
|
}
|
|
181
|
+
/**
|
|
182
|
+
* Get color for capability origin.
|
|
183
|
+
*
|
|
184
|
+
* Returns the color associated with each origin type:
|
|
185
|
+
* - BuiltIn: Cyan
|
|
186
|
+
* - UserProvided: Green
|
|
187
|
+
* - Indirect: Purple
|
|
188
|
+
*/
|
|
189
|
+
export function getOriginColor(origin) {
|
|
190
|
+
return originColors[origin];
|
|
191
|
+
}
|
|
174
192
|
/**
|
|
175
193
|
* Get text color based on current/historical state.
|
|
176
194
|
*
|
|
@@ -220,6 +238,7 @@ export const STATUS_ICONS = {
|
|
|
220
238
|
[ExecutionStatus.Success]: '✓ ',
|
|
221
239
|
[ExecutionStatus.Failed]: '✗ ',
|
|
222
240
|
[ExecutionStatus.Aborted]: '⊘ ',
|
|
241
|
+
[ExecutionStatus.Cancelled]: '⊘ ',
|
|
223
242
|
};
|
|
224
243
|
/**
|
|
225
244
|
* Get colors for different execution status states.
|
|
@@ -249,7 +268,7 @@ export function getStatusColors(status) {
|
|
|
249
268
|
case ExecutionStatus.Success:
|
|
250
269
|
return {
|
|
251
270
|
icon: Colors.Status.Success,
|
|
252
|
-
description:
|
|
271
|
+
description: Palette.AshGray,
|
|
253
272
|
command: Palette.Gray,
|
|
254
273
|
symbol: Palette.Gray,
|
|
255
274
|
};
|
|
@@ -262,10 +281,17 @@ export function getStatusColors(status) {
|
|
|
262
281
|
};
|
|
263
282
|
case ExecutionStatus.Aborted:
|
|
264
283
|
return {
|
|
265
|
-
icon: Palette.
|
|
266
|
-
description:
|
|
267
|
-
command: Palette.
|
|
284
|
+
icon: Palette.MediumOrange,
|
|
285
|
+
description: Palette.Gray,
|
|
286
|
+
command: Palette.MediumOrange,
|
|
268
287
|
symbol: Palette.Gray,
|
|
269
288
|
};
|
|
289
|
+
case ExecutionStatus.Cancelled:
|
|
290
|
+
return {
|
|
291
|
+
icon: Palette.DarkGray,
|
|
292
|
+
description: Palette.DarkGray,
|
|
293
|
+
command: Palette.DarkGray,
|
|
294
|
+
symbol: Palette.DarkGray,
|
|
295
|
+
};
|
|
270
296
|
}
|
|
271
297
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { randomUUID } from 'node:crypto';
|
|
2
2
|
import { existsSync, readFileSync } from 'node:fs';
|
|
3
|
-
import { ComponentName } from '../types/types.js';
|
|
4
|
-
import { ComponentStatus, } from '../types/components.js';
|
|
5
3
|
import { parse as parseYaml } from 'yaml';
|
|
4
|
+
import { ComponentStatus, } from '../types/components.js';
|
|
5
|
+
import { ComponentName } from '../types/types.js';
|
|
6
6
|
import { ConfigDefinitionType, getConfigPath, getConfigSchema, loadConfig, } from './configuration.js';
|
|
7
7
|
import { getConfirmationMessage } from './messages.js';
|
|
8
8
|
import { StepType } from '../ui/Config.js';
|
|
@@ -78,7 +78,7 @@ export function createConfigStepsFromSchema(keys) {
|
|
|
78
78
|
// Config file doesn't exist or can't be parsed
|
|
79
79
|
}
|
|
80
80
|
return keys.map((key) => {
|
|
81
|
-
// Check if key is in schema (
|
|
81
|
+
// Check if key is in schema (system config)
|
|
82
82
|
if (!(key in schema)) {
|
|
83
83
|
// Key is not in schema - it's from a skill or discovered config
|
|
84
84
|
// Create a simple text step with the full path as description
|
|
@@ -180,7 +180,11 @@ export function createConfigDefinition(onFinished, onAborted) {
|
|
|
180
180
|
id: randomUUID(),
|
|
181
181
|
name: ComponentName.Config,
|
|
182
182
|
status: ComponentStatus.Awaiting,
|
|
183
|
-
state: {
|
|
183
|
+
state: {
|
|
184
|
+
values: {},
|
|
185
|
+
completedStep: 0,
|
|
186
|
+
selectedIndex: 0,
|
|
187
|
+
},
|
|
184
188
|
props: {
|
|
185
189
|
steps: createConfigSteps(),
|
|
186
190
|
onFinished,
|
|
@@ -196,7 +200,11 @@ export function createConfigDefinitionWithKeys(keys, onFinished, onAborted) {
|
|
|
196
200
|
id: randomUUID(),
|
|
197
201
|
name: ComponentName.Config,
|
|
198
202
|
status: ComponentStatus.Awaiting,
|
|
199
|
-
state: {
|
|
203
|
+
state: {
|
|
204
|
+
values: {},
|
|
205
|
+
completedStep: 0,
|
|
206
|
+
selectedIndex: 0,
|
|
207
|
+
},
|
|
200
208
|
props: {
|
|
201
209
|
steps: createConfigStepsFromSchema(keys),
|
|
202
210
|
onFinished,
|
|
@@ -338,7 +346,15 @@ export function createExecuteDefinition(tasks, service) {
|
|
|
338
346
|
id: randomUUID(),
|
|
339
347
|
name: ComponentName.Execute,
|
|
340
348
|
status: ComponentStatus.Awaiting,
|
|
341
|
-
state: {
|
|
349
|
+
state: {
|
|
350
|
+
error: null,
|
|
351
|
+
message: '',
|
|
352
|
+
summary: '',
|
|
353
|
+
taskInfos: [],
|
|
354
|
+
completed: 0,
|
|
355
|
+
taskExecutionTimes: [],
|
|
356
|
+
completionMessage: null,
|
|
357
|
+
},
|
|
342
358
|
props: {
|
|
343
359
|
tasks,
|
|
344
360
|
service,
|
|
@@ -350,7 +366,12 @@ export function createValidateDefinition(missingConfig, userRequest, service, on
|
|
|
350
366
|
id: randomUUID(),
|
|
351
367
|
name: ComponentName.Validate,
|
|
352
368
|
status: ComponentStatus.Awaiting,
|
|
353
|
-
state: {
|
|
369
|
+
state: {
|
|
370
|
+
error: null,
|
|
371
|
+
completionMessage: null,
|
|
372
|
+
configRequirements: null,
|
|
373
|
+
validated: false,
|
|
374
|
+
},
|
|
354
375
|
props: {
|
|
355
376
|
missingConfig,
|
|
356
377
|
userRequest,
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
|
|
2
|
+
import { homedir } from 'os';
|
|
3
|
+
import { join } from 'path';
|
|
4
|
+
/**
|
|
5
|
+
* Get the path to the config labels cache file
|
|
6
|
+
*/
|
|
7
|
+
export function getConfigLabelsCachePath() {
|
|
8
|
+
return join(homedir(), '.pls', 'cache', 'config.json');
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Get the cache directory path
|
|
12
|
+
*/
|
|
13
|
+
function getCacheDirectoryPath() {
|
|
14
|
+
return join(homedir(), '.pls', 'cache');
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Ensure the cache directory exists
|
|
18
|
+
*/
|
|
19
|
+
function ensureCacheDirectoryExists() {
|
|
20
|
+
const cacheDir = getCacheDirectoryPath();
|
|
21
|
+
if (!existsSync(cacheDir)) {
|
|
22
|
+
mkdirSync(cacheDir, { recursive: true });
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Load config labels from cache file
|
|
27
|
+
* Returns empty object if file doesn't exist or is corrupted
|
|
28
|
+
*/
|
|
29
|
+
export function loadConfigLabels() {
|
|
30
|
+
try {
|
|
31
|
+
const cachePath = getConfigLabelsCachePath();
|
|
32
|
+
if (!existsSync(cachePath)) {
|
|
33
|
+
return {};
|
|
34
|
+
}
|
|
35
|
+
const content = readFileSync(cachePath, 'utf-8');
|
|
36
|
+
const parsed = JSON.parse(content);
|
|
37
|
+
// Validate that parsed content is an object
|
|
38
|
+
if (typeof parsed !== 'object' ||
|
|
39
|
+
parsed === null ||
|
|
40
|
+
Array.isArray(parsed)) {
|
|
41
|
+
return {};
|
|
42
|
+
}
|
|
43
|
+
return parsed;
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
// Return empty object on any error (parse error, read error, etc.)
|
|
47
|
+
return {};
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Save multiple config labels to cache
|
|
52
|
+
*/
|
|
53
|
+
export function saveConfigLabels(labels) {
|
|
54
|
+
ensureCacheDirectoryExists();
|
|
55
|
+
// Load existing labels and merge with new ones
|
|
56
|
+
const existing = loadConfigLabels();
|
|
57
|
+
const merged = { ...existing, ...labels };
|
|
58
|
+
const cachePath = getConfigLabelsCachePath();
|
|
59
|
+
const content = JSON.stringify(merged, null, 2);
|
|
60
|
+
writeFileSync(cachePath, content, 'utf-8');
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Save a single config label to cache
|
|
64
|
+
*/
|
|
65
|
+
export function saveConfigLabel(key, label) {
|
|
66
|
+
saveConfigLabels({ [key]: label });
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Get a config label from cache
|
|
70
|
+
* Returns undefined if label doesn't exist
|
|
71
|
+
*/
|
|
72
|
+
export function getConfigLabel(key) {
|
|
73
|
+
const labels = loadConfigLabels();
|
|
74
|
+
return labels[key];
|
|
75
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility functions for config manipulation
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Flatten nested config object to dot notation
|
|
6
|
+
* Example: { a: { b: 1 } } => { 'a.b': 1 }
|
|
7
|
+
*/
|
|
8
|
+
export function flattenConfig(obj, prefix = '') {
|
|
9
|
+
const result = {};
|
|
10
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
11
|
+
const fullKey = prefix ? `${prefix}.${key}` : key;
|
|
12
|
+
if (value && typeof value === 'object' && !Array.isArray(value)) {
|
|
13
|
+
Object.assign(result, flattenConfig(value, fullKey));
|
|
14
|
+
}
|
|
15
|
+
else {
|
|
16
|
+
result[fullKey] = value;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return result;
|
|
20
|
+
}
|
|
@@ -2,6 +2,18 @@ import { existsSync, readFileSync, writeFileSync } from 'fs';
|
|
|
2
2
|
import { homedir } from 'os';
|
|
3
3
|
import { join } from 'path';
|
|
4
4
|
import YAML from 'yaml';
|
|
5
|
+
import { getConfigLabel } from './config-labels.js';
|
|
6
|
+
import { flattenConfig } from './config-utils.js';
|
|
7
|
+
/**
|
|
8
|
+
* Convert a dotted config key to a readable label
|
|
9
|
+
* Example: "project.alpha.repo" -> "Project Alpha Repo"
|
|
10
|
+
*/
|
|
11
|
+
function keyToLabel(key) {
|
|
12
|
+
return key
|
|
13
|
+
.split('.')
|
|
14
|
+
.map((part) => part.charAt(0).toUpperCase() + part.slice(1))
|
|
15
|
+
.join(' ');
|
|
16
|
+
}
|
|
5
17
|
export var AnthropicModel;
|
|
6
18
|
(function (AnthropicModel) {
|
|
7
19
|
AnthropicModel["Sonnet"] = "claude-sonnet-4-5";
|
|
@@ -192,7 +204,7 @@ export function getConfigurationRequiredMessage(forFutureUse = false) {
|
|
|
192
204
|
return messages[Math.floor(Math.random() * messages.length)];
|
|
193
205
|
}
|
|
194
206
|
/**
|
|
195
|
-
* Core configuration schema - defines structure and types for
|
|
207
|
+
* Core configuration schema - defines structure and types for system settings
|
|
196
208
|
*/
|
|
197
209
|
const coreConfigSchema = {
|
|
198
210
|
'anthropic.key': {
|
|
@@ -301,19 +313,6 @@ export function getConfiguredKeys() {
|
|
|
301
313
|
const content = readFileSync(configFile, 'utf-8');
|
|
302
314
|
const parsed = YAML.parse(content);
|
|
303
315
|
// Flatten nested config to dot notation
|
|
304
|
-
function flattenConfig(obj, prefix = '') {
|
|
305
|
-
const result = {};
|
|
306
|
-
for (const [key, value] of Object.entries(obj)) {
|
|
307
|
-
const fullKey = prefix ? `${prefix}.${key}` : key;
|
|
308
|
-
if (value && typeof value === 'object' && !Array.isArray(value)) {
|
|
309
|
-
Object.assign(result, flattenConfig(value, fullKey));
|
|
310
|
-
}
|
|
311
|
-
else {
|
|
312
|
-
result[fullKey] = value;
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
return result;
|
|
316
|
-
}
|
|
317
316
|
const flatConfig = flattenConfig(parsed);
|
|
318
317
|
return Object.keys(flatConfig);
|
|
319
318
|
}
|
|
@@ -337,19 +336,6 @@ export function getAvailableConfigStructure() {
|
|
|
337
336
|
const content = readFileSync(configFile, 'utf-8');
|
|
338
337
|
const parsed = YAML.parse(content);
|
|
339
338
|
// Flatten nested config to dot notation
|
|
340
|
-
function flattenConfig(obj, prefix = '') {
|
|
341
|
-
const result = {};
|
|
342
|
-
for (const [key, value] of Object.entries(obj)) {
|
|
343
|
-
const fullKey = prefix ? `${prefix}.${key}` : key;
|
|
344
|
-
if (value && typeof value === 'object' && !Array.isArray(value)) {
|
|
345
|
-
Object.assign(result, flattenConfig(value, fullKey));
|
|
346
|
-
}
|
|
347
|
-
else {
|
|
348
|
-
result[fullKey] = value;
|
|
349
|
-
}
|
|
350
|
-
}
|
|
351
|
-
return result;
|
|
352
|
-
}
|
|
353
339
|
flatConfig = flattenConfig(parsed);
|
|
354
340
|
}
|
|
355
341
|
}
|
|
@@ -357,20 +343,13 @@ export function getAvailableConfigStructure() {
|
|
|
357
343
|
// Config file doesn't exist or can't be read
|
|
358
344
|
}
|
|
359
345
|
// Add schema keys with descriptions
|
|
360
|
-
// Mark optional keys as (optional)
|
|
361
346
|
for (const [key, definition] of Object.entries(schema)) {
|
|
362
|
-
|
|
363
|
-
if (isOptional) {
|
|
364
|
-
structure[key] = `${definition.description} (optional)`;
|
|
365
|
-
}
|
|
366
|
-
else {
|
|
367
|
-
structure[key] = definition.description;
|
|
368
|
-
}
|
|
347
|
+
structure[key] = definition.description;
|
|
369
348
|
}
|
|
370
349
|
// Add discovered keys that aren't in schema
|
|
371
350
|
for (const key of Object.keys(flatConfig)) {
|
|
372
351
|
if (!(key in structure)) {
|
|
373
|
-
structure[key] =
|
|
352
|
+
structure[key] = getConfigLabel(key) || keyToLabel(key);
|
|
374
353
|
}
|
|
375
354
|
}
|
|
376
355
|
return structure;
|
|
@@ -32,7 +32,7 @@ class ToolRegistry {
|
|
|
32
32
|
}
|
|
33
33
|
// Create singleton instance
|
|
34
34
|
export const toolRegistry = new ToolRegistry();
|
|
35
|
-
// Register
|
|
35
|
+
// Register system tools
|
|
36
36
|
import { answerTool } from '../tools/answer.tool.js';
|
|
37
37
|
import { configureTool } from '../tools/configure.tool.js';
|
|
38
38
|
import { executeTool } from '../tools/execute.tool.js';
|
package/dist/services/router.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { asScheduledTasks } from '../types/guards.js';
|
|
2
|
+
import { FeedbackType, TaskType } from '../types/types.js';
|
|
2
3
|
import { createAnswerDefinition, createConfigDefinitionWithKeys, createConfirmDefinition, createExecuteDefinition, createFeedback, createIntrospectDefinition, createMessage, createScheduleDefinition, createValidateDefinition, } from './components.js';
|
|
3
4
|
import { saveConfig, unflattenConfig } from './configuration.js';
|
|
4
|
-
import { FeedbackType } from '../types/types.js';
|
|
5
|
-
import { validateExecuteTasks } from './validator.js';
|
|
6
5
|
import { getCancellationMessage, getMixedTaskTypesError, getUnknownRequestMessage, } from './messages.js';
|
|
6
|
+
import { validateExecuteTasks } from './validator.js';
|
|
7
7
|
/**
|
|
8
8
|
* Determine the operation name based on task types
|
|
9
9
|
*/
|
|
@@ -67,8 +67,8 @@ export function routeTasksWithConfirm(tasks, message, service, userRequest, hand
|
|
|
67
67
|
function validateTaskTypes(tasks) {
|
|
68
68
|
if (tasks.length === 0)
|
|
69
69
|
return;
|
|
70
|
-
//
|
|
71
|
-
const scheduledTasks = tasks;
|
|
70
|
+
// Convert to ScheduledTask to access subtasks property
|
|
71
|
+
const scheduledTasks = asScheduledTasks(tasks);
|
|
72
72
|
// Check each Group task's subtasks for uniform types
|
|
73
73
|
for (const task of scheduledTasks) {
|
|
74
74
|
if (task.type === TaskType.Group &&
|
|
@@ -97,7 +97,7 @@ function executeTasksAfterConfirm(tasks, service, userRequest, handlers) {
|
|
|
97
97
|
handlers.onError(error instanceof Error ? error.message : String(error));
|
|
98
98
|
return;
|
|
99
99
|
}
|
|
100
|
-
const scheduledTasks = tasks;
|
|
100
|
+
const scheduledTasks = asScheduledTasks(tasks);
|
|
101
101
|
// Process tasks in order, preserving Group boundaries
|
|
102
102
|
// Track consecutive standalone tasks to group them by type
|
|
103
103
|
let consecutiveStandaloneTasks = [];
|
package/dist/services/shell.js
CHANGED
|
@@ -5,6 +5,7 @@ export var ExecutionStatus;
|
|
|
5
5
|
ExecutionStatus["Success"] = "success";
|
|
6
6
|
ExecutionStatus["Failed"] = "failed";
|
|
7
7
|
ExecutionStatus["Aborted"] = "aborted";
|
|
8
|
+
ExecutionStatus["Cancelled"] = "cancelled";
|
|
8
9
|
})(ExecutionStatus || (ExecutionStatus = {}));
|
|
9
10
|
export var ExecutionResult;
|
|
10
11
|
(function (ExecutionResult) {
|
package/dist/services/skills.js
CHANGED
|
@@ -32,7 +32,7 @@ export function isValidSkillFilename(filename) {
|
|
|
32
32
|
return kebabCasePattern.test(name);
|
|
33
33
|
}
|
|
34
34
|
/**
|
|
35
|
-
* Check if skill key conflicts with
|
|
35
|
+
* Check if skill key conflicts with system skills
|
|
36
36
|
*/
|
|
37
37
|
export function conflictsWithBuiltIn(key) {
|
|
38
38
|
return BUILT_IN_SKILLS.has(key);
|
|
@@ -46,7 +46,7 @@ export function getSkillsDirectory() {
|
|
|
46
46
|
/**
|
|
47
47
|
* Load all skill markdown files from the skills directory
|
|
48
48
|
* Returns an array of objects with filename (key) and content
|
|
49
|
-
* Filters out invalid filenames and conflicts with
|
|
49
|
+
* Filters out invalid filenames and conflicts with system skills
|
|
50
50
|
*/
|
|
51
51
|
export function loadSkills() {
|
|
52
52
|
const skillsDir = getSkillsDirectory();
|
|
@@ -65,7 +65,7 @@ export function loadSkills() {
|
|
|
65
65
|
}
|
|
66
66
|
// Extract key (filename without extension, handles both .md and .MD)
|
|
67
67
|
const key = file.slice(0, -3);
|
|
68
|
-
// Must not conflict with
|
|
68
|
+
// Must not conflict with system skills
|
|
69
69
|
if (conflictsWithBuiltIn(key)) {
|
|
70
70
|
return false;
|
|
71
71
|
}
|
|
@@ -26,8 +26,8 @@ You will receive:
|
|
|
26
26
|
|
|
27
27
|
## Task
|
|
28
28
|
|
|
29
|
-
Present the concierge's capabilities as a list of
|
|
30
|
-
|
|
29
|
+
Present the concierge's capabilities as a list of capability objects, each
|
|
30
|
+
with a name, description, and origin.
|
|
31
31
|
|
|
32
32
|
## Response Format
|
|
33
33
|
|
|
@@ -77,7 +77,7 @@ NON-NEGOTIABLE and applies to EVERY response.
|
|
|
77
77
|
|
|
78
78
|
**CORRECT ORDER - FOLLOW EXACTLY:**
|
|
79
79
|
|
|
80
|
-
### Position 1-4:
|
|
80
|
+
### Position 1-4: system capabilities (origin: "system")
|
|
81
81
|
|
|
82
82
|
These MUST appear FIRST, in this EXACT sequence:
|
|
83
83
|
|
|
@@ -86,47 +86,56 @@ These MUST appear FIRST, in this EXACT sequence:
|
|
|
86
86
|
3. **Answer** ← ALWAYS THIRD
|
|
87
87
|
4. **Execute** ← ALWAYS FOURTH
|
|
88
88
|
|
|
89
|
-
### Position 5-7:
|
|
89
|
+
### Position 5-7: meta workflow capabilities (origin: "meta")
|
|
90
90
|
|
|
91
|
-
These MUST appear AFTER Execute and BEFORE user skills:
|
|
91
|
+
These MUST appear AFTER Execute and BEFORE user-provided skills:
|
|
92
92
|
|
|
93
93
|
5. **Schedule** ← NEVER FIRST, ALWAYS position 5 (after Execute)
|
|
94
94
|
6. **Validate** ← ALWAYS position 6 (after Schedule)
|
|
95
95
|
7. **Report** ← NEVER FIRST, ALWAYS position 7 (after Validate)
|
|
96
96
|
|
|
97
|
-
### 3.
|
|
97
|
+
### 3. user-provided skills (origin: "user")
|
|
98
98
|
|
|
99
99
|
If skills are provided in the "Available Skills" section below, include
|
|
100
100
|
them in the response. For each skill:
|
|
101
101
|
- Extract the skill name from the first heading (# Skill Name)
|
|
102
|
-
-
|
|
103
|
-
|
|
102
|
+
- Set origin to "user"
|
|
103
|
+
- If the skill name contains "(INCOMPLETE)", set isIncomplete to true and
|
|
104
|
+
remove "(INCOMPLETE)" from the name
|
|
104
105
|
- Extract a brief description from the Description or Overview section
|
|
105
106
|
- Keep descriptions concise (1-2 lines maximum)
|
|
106
107
|
- If the user specified a filter (e.g., "skills for deployment"), only
|
|
107
108
|
include skills whose name or description matches the filter
|
|
108
109
|
|
|
109
|
-
##
|
|
110
|
+
## Capability Object Guidelines
|
|
110
111
|
|
|
111
|
-
Create
|
|
112
|
+
Create capability objects for each capability. Each object should have:
|
|
112
113
|
|
|
113
|
-
- **
|
|
114
|
-
-
|
|
115
|
-
|
|
116
|
-
-
|
|
117
|
-
|
|
114
|
+
- **name**: The capability or skill name
|
|
115
|
+
- Use title case (e.g., "Schedule", "Execute", "Deploy Application")
|
|
116
|
+
- NOT all uppercase (NOT "SCHEDULE", "EXECUTE")
|
|
117
|
+
- Maximum 32 characters
|
|
118
|
+
- Examples: "Introspect", "Execute", "Deploy Application"
|
|
119
|
+
|
|
120
|
+
- **description**: A concise description of what this capability does
|
|
121
|
+
- Maximum 64 characters
|
|
122
|
+
- Start with lowercase letter, no ending punctuation
|
|
123
|
+
- Focus on clarity and brevity
|
|
124
|
+
- Describe the core purpose in one short phrase
|
|
118
125
|
- Examples:
|
|
119
|
-
- "
|
|
120
|
-
- "
|
|
121
|
-
- "
|
|
122
|
-
|
|
123
|
-
- **
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
-
|
|
127
|
-
-
|
|
128
|
-
|
|
129
|
-
-
|
|
126
|
+
- "break down requests into actionable steps"
|
|
127
|
+
- "run shell commands and process operations"
|
|
128
|
+
- "build and deploy to staging or production"
|
|
129
|
+
|
|
130
|
+
- **origin**: The origin type of the capability
|
|
131
|
+
- Use "system" for system capabilities: Introspect, Configure, Answer,
|
|
132
|
+
Execute
|
|
133
|
+
- Use "meta" for meta workflow capabilities: Schedule, Validate, Report
|
|
134
|
+
- Use "user" for all user-provided skills
|
|
135
|
+
|
|
136
|
+
- **isIncomplete**: Optional boolean flag
|
|
137
|
+
- Only include if the skill is marked as incomplete
|
|
138
|
+
- Set to true if skill name contained "(INCOMPLETE)"
|
|
130
139
|
|
|
131
140
|
## Filtering
|
|
132
141
|
|
|
@@ -134,48 +143,48 @@ When the user specifies a filter (e.g., "skills for deployment", "what
|
|
|
134
143
|
can you do with files"):
|
|
135
144
|
1. Parse the filter keyword(s) from the request
|
|
136
145
|
2. Match against skill names and descriptions (case-insensitive)
|
|
137
|
-
3. Include
|
|
146
|
+
3. Include system capabilities if they match the filter
|
|
138
147
|
4. Only present capabilities that match the filter
|
|
139
148
|
|
|
140
149
|
Examples:
|
|
141
150
|
- "skills for deployment" → Only show skills with "deploy" in
|
|
142
151
|
name/description
|
|
143
152
|
- "what can you do with files" → Show EXECUTE and any file-related skills
|
|
144
|
-
- "list all skills" → Show all
|
|
153
|
+
- "list all skills" → Show all system capabilities + all user-provided skills
|
|
145
154
|
|
|
146
155
|
## Examples
|
|
147
156
|
|
|
148
157
|
### Example 1: List All Capabilities
|
|
149
158
|
|
|
150
159
|
When user asks "list your skills", create an introductory message like
|
|
151
|
-
"here are my capabilities:" followed by
|
|
152
|
-
(Introspect, Configure, Answer, Execute
|
|
153
|
-
(Schedule, Validate, Report
|
|
154
|
-
|
|
155
|
-
Each task uses type "introspect" with an action describing the
|
|
156
|
-
capability.
|
|
160
|
+
"here are my capabilities:" followed by capability objects for system
|
|
161
|
+
capabilities (Introspect, Configure, Answer, Execute with origin
|
|
162
|
+
"system"), then meta workflow capabilities (Schedule, Validate, Report
|
|
163
|
+
with origin "meta").
|
|
157
164
|
|
|
158
165
|
### Example 2: Filtered Skills
|
|
159
166
|
|
|
160
167
|
When user asks "skills for deployment" and a "deploy app" skill exists,
|
|
161
168
|
create an introductory message like "these skills match 'deployment':"
|
|
162
|
-
followed by only the
|
|
163
|
-
|
|
169
|
+
followed by only the capabilities that match the filter. Show the deploy
|
|
170
|
+
app skill with origin "user".
|
|
164
171
|
|
|
165
172
|
### Example 3: With User Skills
|
|
166
173
|
|
|
167
|
-
When user asks "what can you do" and user-
|
|
174
|
+
When user asks "what can you do" and user-provided skills like "process
|
|
168
175
|
data" and "backup files" exist, create an introductory message like "i can
|
|
169
|
-
help with these operations:" followed by all
|
|
170
|
-
(Introspect, Configure, Answer, Execute
|
|
171
|
-
|
|
172
|
-
"
|
|
176
|
+
help with these operations:" followed by all system capabilities
|
|
177
|
+
(Introspect, Configure, Answer, Execute with origin "system"), meta
|
|
178
|
+
capabilities (Schedule, Validate, Report with origin "meta"), plus the
|
|
179
|
+
user-provided skills with origin "user".
|
|
173
180
|
|
|
174
181
|
## Final Validation
|
|
175
182
|
|
|
176
183
|
Before finalizing:
|
|
177
|
-
1. Ensure every
|
|
178
|
-
|
|
184
|
+
1. Ensure every capability has the correct origin value ("system",
|
|
185
|
+
"meta", or "user")
|
|
186
|
+
2. Verify descriptions are concise (≤64 characters)
|
|
179
187
|
3. Confirm the introductory message ends with a colon
|
|
180
188
|
4. Check that filtering was applied correctly if specified
|
|
181
189
|
5. Ensure no duplicate capabilities are listed
|
|
190
|
+
6. Verify names use title case, not all uppercase
|