prompt-language-shell 0.4.0 → 0.4.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/config/INTROSPECT.md +18 -13
- package/dist/config/PLAN.md +1 -1
- package/dist/services/components.js +27 -0
- package/dist/types/types.js +2 -0
- package/dist/ui/Component.js +9 -0
- package/dist/ui/Introspect.js +98 -0
- package/dist/ui/Main.js +67 -3
- package/dist/ui/Report.js +13 -0
- package/package.json +1 -1
|
@@ -59,13 +59,13 @@ Present capabilities in two categories:
|
|
|
59
59
|
|
|
60
60
|
These are the core operations available to all users:
|
|
61
61
|
|
|
62
|
-
- **
|
|
63
|
-
- **
|
|
62
|
+
- **Config**: Configuration changes, settings updates
|
|
63
|
+
- **Plan**: Plan and structure tasks from natural language requests, breaking
|
|
64
64
|
them down into clear, actionable steps
|
|
65
|
-
- **
|
|
66
|
-
- **
|
|
67
|
-
- **
|
|
68
|
-
- **
|
|
65
|
+
- **Introspect**: List and describe available capabilities and skills
|
|
66
|
+
- **Answer**: Answer questions, explain concepts, provide information
|
|
67
|
+
- **Execute**: Run shell commands, execute programs, process operations
|
|
68
|
+
- **Report**: Generate summaries, create reports, display results
|
|
69
69
|
|
|
70
70
|
### 2. User-Defined Skills
|
|
71
71
|
|
|
@@ -82,15 +82,20 @@ in the response. For each skill:
|
|
|
82
82
|
Create tasks with type "introspect" for each capability. Each task should:
|
|
83
83
|
|
|
84
84
|
- **Action**: The capability name and a concise description
|
|
85
|
-
- Format: "
|
|
85
|
+
- Format: "Capability Name: description" (note: display format will use " - " separator)
|
|
86
|
+
- **IMPORTANT**: Use title case for capability names (e.g., "Plan", "Execute"), NOT all uppercase (NOT "PLAN", "EXECUTE")
|
|
86
87
|
- Examples:
|
|
87
|
-
- "
|
|
88
|
-
- "
|
|
89
|
-
- "Deploy Application:
|
|
88
|
+
- "Plan: break down requests into actionable steps"
|
|
89
|
+
- "Execute: run shell commands and process operations"
|
|
90
|
+
- "Deploy Application: build and deploy to staging or production"
|
|
90
91
|
- **Type**: Always use "introspect"
|
|
91
92
|
- **Params**: Omit params field
|
|
92
93
|
|
|
93
|
-
**Keep action descriptions concise
|
|
94
|
+
**Keep action descriptions concise:**
|
|
95
|
+
- Maximum 60 characters for the description portion (after the colon)
|
|
96
|
+
- Focus on clarity and brevity
|
|
97
|
+
- Describe the core purpose in one short phrase
|
|
98
|
+
- Start descriptions with a lowercase letter (they follow a colon)
|
|
94
99
|
|
|
95
100
|
## Filtering
|
|
96
101
|
|
|
@@ -111,8 +116,8 @@ Examples:
|
|
|
111
116
|
### Example 1: List All Capabilities
|
|
112
117
|
|
|
113
118
|
When user asks "list your skills", create an introductory message like "here
|
|
114
|
-
are my capabilities:" followed by a task for each built-in capability:
|
|
115
|
-
|
|
119
|
+
are my capabilities:" followed by a task for each built-in capability: Plan,
|
|
120
|
+
Introspect, Answer, Execute, Report, and Config. Each task uses type
|
|
116
121
|
"introspect" with an action describing the capability.
|
|
117
122
|
|
|
118
123
|
### Example 2: Filtered Skills
|
package/dist/config/PLAN.md
CHANGED
|
@@ -237,7 +237,7 @@ Examples that should be aborted as offensive:
|
|
|
237
237
|
capabilities or skills:
|
|
238
238
|
- Verbs: "list skills", "show skills", "what can you do", "list
|
|
239
239
|
capabilities", "show capabilities", "what skills", "describe skills",
|
|
240
|
-
"flex", "show off"
|
|
240
|
+
"introspect", "flex", "show off"
|
|
241
241
|
- **Filtering**: If the request specifies a category, domain, or context
|
|
242
242
|
(e.g., "for deployment", "related to files", "about testing"), add a
|
|
243
243
|
params object with a filter field containing the specified context
|
|
@@ -125,6 +125,33 @@ export function createConfirmDefinition(onConfirmed, onCancelled) {
|
|
|
125
125
|
},
|
|
126
126
|
};
|
|
127
127
|
}
|
|
128
|
+
export function createIntrospectDefinition(tasks, service, onError, onComplete, onAborted) {
|
|
129
|
+
return {
|
|
130
|
+
id: randomUUID(),
|
|
131
|
+
name: ComponentName.Introspect,
|
|
132
|
+
state: {
|
|
133
|
+
done: false,
|
|
134
|
+
isLoading: true,
|
|
135
|
+
},
|
|
136
|
+
props: {
|
|
137
|
+
tasks,
|
|
138
|
+
service,
|
|
139
|
+
onError,
|
|
140
|
+
onComplete,
|
|
141
|
+
onAborted,
|
|
142
|
+
},
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
export function createReportDefinition(message, capabilities) {
|
|
146
|
+
return {
|
|
147
|
+
id: randomUUID(),
|
|
148
|
+
name: ComponentName.Report,
|
|
149
|
+
props: {
|
|
150
|
+
message,
|
|
151
|
+
capabilities,
|
|
152
|
+
},
|
|
153
|
+
};
|
|
154
|
+
}
|
|
128
155
|
export function isStateless(component) {
|
|
129
156
|
return !('state' in component);
|
|
130
157
|
}
|
package/dist/types/types.js
CHANGED
|
@@ -8,6 +8,8 @@ export var ComponentName;
|
|
|
8
8
|
ComponentName["Refinement"] = "refinement";
|
|
9
9
|
ComponentName["Feedback"] = "feedback";
|
|
10
10
|
ComponentName["Confirm"] = "confirm";
|
|
11
|
+
ComponentName["Introspect"] = "introspect";
|
|
12
|
+
ComponentName["Report"] = "report";
|
|
11
13
|
})(ComponentName || (ComponentName = {}));
|
|
12
14
|
export var TaskType;
|
|
13
15
|
(function (TaskType) {
|
package/dist/ui/Component.js
CHANGED
|
@@ -5,9 +5,11 @@ import { Command } from './Command.js';
|
|
|
5
5
|
import { Confirm } from './Confirm.js';
|
|
6
6
|
import { Config } from './Config.js';
|
|
7
7
|
import { Feedback } from './Feedback.js';
|
|
8
|
+
import { Introspect } from './Introspect.js';
|
|
8
9
|
import { Message } from './Message.js';
|
|
9
10
|
import { Plan } from './Plan.js';
|
|
10
11
|
import { Refinement } from './Refinement.js';
|
|
12
|
+
import { Report } from './Report.js';
|
|
11
13
|
import { Welcome } from './Welcome.js';
|
|
12
14
|
export const Component = React.memo(function Component({ def, debug, }) {
|
|
13
15
|
switch (def.name) {
|
|
@@ -39,5 +41,12 @@ export const Component = React.memo(function Component({ def, debug, }) {
|
|
|
39
41
|
const state = def.state;
|
|
40
42
|
return _jsx(Confirm, { ...props, state: state });
|
|
41
43
|
}
|
|
44
|
+
case ComponentName.Introspect: {
|
|
45
|
+
const props = def.props;
|
|
46
|
+
const state = def.state;
|
|
47
|
+
return _jsx(Introspect, { ...props, state: state });
|
|
48
|
+
}
|
|
49
|
+
case ComponentName.Report:
|
|
50
|
+
return _jsx(Report, { ...def.props });
|
|
42
51
|
}
|
|
43
52
|
});
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useState } from 'react';
|
|
3
|
+
import { Box, Text, useInput } from 'ink';
|
|
4
|
+
import { Spinner } from './Spinner.js';
|
|
5
|
+
const MIN_PROCESSING_TIME = 1000;
|
|
6
|
+
const BUILT_IN_CAPABILITIES = new Set([
|
|
7
|
+
'CONFIG',
|
|
8
|
+
'PLAN',
|
|
9
|
+
'INTROSPECT',
|
|
10
|
+
'ANSWER',
|
|
11
|
+
'EXECUTE',
|
|
12
|
+
'REPORT',
|
|
13
|
+
]);
|
|
14
|
+
function parseCapabilityFromTask(task) {
|
|
15
|
+
// Parse "NAME: Description" format from task.action
|
|
16
|
+
const colonIndex = task.action.indexOf(':');
|
|
17
|
+
if (colonIndex === -1) {
|
|
18
|
+
return {
|
|
19
|
+
name: task.action,
|
|
20
|
+
description: '',
|
|
21
|
+
isBuiltIn: BUILT_IN_CAPABILITIES.has(task.action.toUpperCase()),
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
const name = task.action.substring(0, colonIndex).trim();
|
|
25
|
+
const description = task.action.substring(colonIndex + 1).trim();
|
|
26
|
+
const isBuiltIn = BUILT_IN_CAPABILITIES.has(name.toUpperCase());
|
|
27
|
+
return {
|
|
28
|
+
name,
|
|
29
|
+
description,
|
|
30
|
+
isBuiltIn,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
export function Introspect({ tasks, state, service, children, onError, onComplete, onAborted, }) {
|
|
34
|
+
const done = state?.done ?? false;
|
|
35
|
+
const [error, setError] = useState(null);
|
|
36
|
+
const [isLoading, setIsLoading] = useState(state?.isLoading ?? !done);
|
|
37
|
+
useInput((input, key) => {
|
|
38
|
+
if (key.escape && isLoading && !done) {
|
|
39
|
+
setIsLoading(false);
|
|
40
|
+
onAborted();
|
|
41
|
+
}
|
|
42
|
+
}, { isActive: isLoading && !done });
|
|
43
|
+
useEffect(() => {
|
|
44
|
+
// Skip processing if done
|
|
45
|
+
if (done) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
// Skip processing if no service available
|
|
49
|
+
if (!service) {
|
|
50
|
+
setError('No service available');
|
|
51
|
+
setIsLoading(false);
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
let mounted = true;
|
|
55
|
+
async function process(svc) {
|
|
56
|
+
const startTime = Date.now();
|
|
57
|
+
try {
|
|
58
|
+
// Get the introspect task action (first task should have the intro message)
|
|
59
|
+
const introspectAction = tasks[0]?.action || 'list capabilities';
|
|
60
|
+
// Call introspect tool
|
|
61
|
+
const result = await svc.processWithTool(introspectAction, 'introspect');
|
|
62
|
+
const elapsed = Date.now() - startTime;
|
|
63
|
+
const remainingTime = Math.max(0, MIN_PROCESSING_TIME - elapsed);
|
|
64
|
+
await new Promise((resolve) => setTimeout(resolve, remainingTime));
|
|
65
|
+
if (mounted) {
|
|
66
|
+
// Parse capabilities from returned tasks
|
|
67
|
+
const capabilities = result.tasks.map(parseCapabilityFromTask);
|
|
68
|
+
setIsLoading(false);
|
|
69
|
+
onComplete?.(result.message, capabilities);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
catch (err) {
|
|
73
|
+
const elapsed = Date.now() - startTime;
|
|
74
|
+
const remainingTime = Math.max(0, MIN_PROCESSING_TIME - elapsed);
|
|
75
|
+
await new Promise((resolve) => setTimeout(resolve, remainingTime));
|
|
76
|
+
if (mounted) {
|
|
77
|
+
const errorMessage = err instanceof Error ? err.message : 'Unknown error occurred';
|
|
78
|
+
setIsLoading(false);
|
|
79
|
+
if (onError) {
|
|
80
|
+
onError(errorMessage);
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
setError(errorMessage);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
process(service);
|
|
89
|
+
return () => {
|
|
90
|
+
mounted = false;
|
|
91
|
+
};
|
|
92
|
+
}, [tasks, done, service]);
|
|
93
|
+
// Don't render wrapper when done and nothing to show
|
|
94
|
+
if (!isLoading && !error && !children) {
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
return (_jsxs(Box, { alignSelf: "flex-start", flexDirection: "column", children: [isLoading && (_jsxs(Box, { children: [_jsx(Text, { children: "Listing capabilities. " }), _jsx(Spinner, {})] })), error && (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: "red", children: ["Error: ", error] }) })), children] }));
|
|
98
|
+
}
|
package/dist/ui/Main.js
CHANGED
|
@@ -5,7 +5,7 @@ import { ComponentName, FeedbackType, TaskType, } from '../types/types.js';
|
|
|
5
5
|
import { createAnthropicService, } from '../services/anthropic.js';
|
|
6
6
|
import { getConfigurationRequiredMessage, hasValidAnthropicKey, loadConfig, loadDebugSetting, saveAnthropicConfig, saveDebugSetting, } from '../services/config.js';
|
|
7
7
|
import { FeedbackMessages, getCancellationMessage, getRefiningMessage, } from '../services/messages.js';
|
|
8
|
-
import { createCommandDefinition, createConfirmDefinition, createConfigDefinition, createFeedback, createMessage, createRefinement,
|
|
8
|
+
import { createCommandDefinition, createConfirmDefinition, createConfigDefinition, createFeedback, createIntrospectDefinition, createMessage, createPlanDefinition, createRefinement, createReportDefinition, createWelcomeDefinition, isStateless, markAsDone, } from '../services/components.js';
|
|
9
9
|
import { exitApp } from '../services/process.js';
|
|
10
10
|
import { Column } from './Column.js';
|
|
11
11
|
export const Main = ({ app, command }) => {
|
|
@@ -95,18 +95,82 @@ export const Main = ({ app, command }) => {
|
|
|
95
95
|
const handleRefinementAborted = React.useCallback(() => {
|
|
96
96
|
handleAborted('Plan refinement');
|
|
97
97
|
}, [handleAborted]);
|
|
98
|
+
const handleIntrospectAborted = React.useCallback(() => {
|
|
99
|
+
handleAborted('Introspection');
|
|
100
|
+
}, [handleAborted]);
|
|
101
|
+
const handleIntrospectError = React.useCallback((error) => {
|
|
102
|
+
setQueue((currentQueue) => {
|
|
103
|
+
if (currentQueue.length === 0)
|
|
104
|
+
return currentQueue;
|
|
105
|
+
const [first] = currentQueue;
|
|
106
|
+
if (first.name === ComponentName.Introspect) {
|
|
107
|
+
addToTimeline(markAsDone(first), createFeedback(FeedbackType.Failed, FeedbackMessages.UnexpectedError, error));
|
|
108
|
+
}
|
|
109
|
+
exitApp(1);
|
|
110
|
+
return [];
|
|
111
|
+
});
|
|
112
|
+
}, [addToTimeline]);
|
|
113
|
+
const handleIntrospectComplete = React.useCallback((message, capabilities) => {
|
|
114
|
+
setQueue((currentQueue) => {
|
|
115
|
+
if (currentQueue.length === 0)
|
|
116
|
+
return currentQueue;
|
|
117
|
+
const [first] = currentQueue;
|
|
118
|
+
if (first.name === ComponentName.Introspect) {
|
|
119
|
+
// Don't add the Introspect component to timeline (it renders null)
|
|
120
|
+
// Only add the Report component
|
|
121
|
+
addToTimeline(createReportDefinition(message, capabilities));
|
|
122
|
+
}
|
|
123
|
+
exitApp(0);
|
|
124
|
+
return [];
|
|
125
|
+
});
|
|
126
|
+
}, [addToTimeline]);
|
|
98
127
|
const handleExecutionConfirmed = React.useCallback(() => {
|
|
99
128
|
setQueue((currentQueue) => {
|
|
100
129
|
if (currentQueue.length === 0)
|
|
101
130
|
return currentQueue;
|
|
102
131
|
const [first] = currentQueue;
|
|
103
132
|
if (first.name === ComponentName.Confirm) {
|
|
104
|
-
|
|
133
|
+
// Find the most recent Plan in timeline to get tasks
|
|
134
|
+
const currentTimeline = timelineRef.current;
|
|
135
|
+
const lastPlanIndex = [...currentTimeline]
|
|
136
|
+
.reverse()
|
|
137
|
+
.findIndex((item) => item.name === ComponentName.Plan);
|
|
138
|
+
const lastPlan = lastPlanIndex >= 0
|
|
139
|
+
? currentTimeline[currentTimeline.length - 1 - lastPlanIndex]
|
|
140
|
+
: null;
|
|
141
|
+
const tasks = lastPlan &&
|
|
142
|
+
lastPlan.name === ComponentName.Plan &&
|
|
143
|
+
'props' in lastPlan &&
|
|
144
|
+
lastPlan.props &&
|
|
145
|
+
'tasks' in lastPlan.props &&
|
|
146
|
+
Array.isArray(lastPlan.props.tasks)
|
|
147
|
+
? lastPlan.props.tasks
|
|
148
|
+
: [];
|
|
149
|
+
const allIntrospect = tasks.every((task) => task.type === TaskType.Introspect);
|
|
150
|
+
if (allIntrospect && tasks.length > 0) {
|
|
151
|
+
// Execute introspection
|
|
152
|
+
addToTimeline(markAsDone(first));
|
|
153
|
+
return [
|
|
154
|
+
createIntrospectDefinition(tasks, service, handleIntrospectError, handleIntrospectComplete, handleIntrospectAborted),
|
|
155
|
+
];
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
// Regular execution - just exit for now
|
|
159
|
+
addToTimeline(markAsDone(first));
|
|
160
|
+
exitApp(0);
|
|
161
|
+
return [];
|
|
162
|
+
}
|
|
105
163
|
}
|
|
106
164
|
exitApp(0);
|
|
107
165
|
return [];
|
|
108
166
|
});
|
|
109
|
-
}, [
|
|
167
|
+
}, [
|
|
168
|
+
addToTimeline,
|
|
169
|
+
service,
|
|
170
|
+
handleIntrospectError,
|
|
171
|
+
handleIntrospectComplete,
|
|
172
|
+
handleIntrospectAborted,
|
|
173
|
+
]);
|
|
110
174
|
const handleExecutionCancelled = React.useCallback(() => {
|
|
111
175
|
setQueue((currentQueue) => {
|
|
112
176
|
if (currentQueue.length === 0)
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Box, Text } from 'ink';
|
|
3
|
+
const COLORS = {
|
|
4
|
+
BuiltIn: '#5c9ccc', // blue - for built-in capabilities
|
|
5
|
+
UserDefined: '#5aaa8a', // green - for user-defined skills
|
|
6
|
+
};
|
|
7
|
+
function CapabilityItem({ name, description, isBuiltIn }) {
|
|
8
|
+
const color = isBuiltIn ? COLORS.BuiltIn : COLORS.UserDefined;
|
|
9
|
+
return (_jsxs(Box, { children: [_jsx(Text, { children: "- " }), _jsx(Text, { color: color, children: name }), _jsxs(Text, { children: [" - ", description] })] }));
|
|
10
|
+
}
|
|
11
|
+
export function Report({ message, capabilities }) {
|
|
12
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { children: message }), _jsx(Box, { flexDirection: "column", marginLeft: 2, marginTop: 1, children: capabilities.map((capability, index) => (_jsx(CapabilityItem, { name: capability.name, description: capability.description, isBuiltIn: capability.isBuiltIn }, index))) })] }));
|
|
13
|
+
}
|